Skip to content

[Security/Deployment] Remove shared default database password from published local stack #195

Description

@seonghobae

Buyer / security gap

Protected develop@622e5e6c3d534f230c390f10e3832efadfc01825 publishes both PostgreSQL containers to host interfaces while assigning a known fallback password when the operator supplies no secret:

postgres:
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-xtrmetl}
  ports:
    - "5432:5432"

postgres-replica:
  POSTGRES_PASSWORD: ${REPLICA_POSTGRES_PASSWORD:-xtrmetl}
  ports:
    - "5433:5432"

The same fallback is propagated into ETL/CDC client credentials. Comments call this local-development-only, but the executable Compose profile does not fail when the password is omitted and the short port syntax does not limit publication to loopback. A known credential plus host-published database is therefore an actual deployment security boundary, not merely documentation style.

Status: known_gap on protected develop. Source mutation is currently defer_until_trigger because active PR #167 owns docker-compose.yml for Zipkin transport and #169 separately owns local runtime cleanup. Do not race either writer; after those lanes stabilize, re-read the exact Compose topology before implementation.

RCA

  • Immediate cause: ${...:-xtrmetl} turns missing database-secret configuration into a valid shared credential.
  • Exposure cause: Compose short port mappings publish PostgreSQL to host network addresses rather than keeping database connectivity only on the Compose network.
  • Technical root cause: the local developer profile conflates convenience defaults, service-to-service credentials, and host access instead of making database secret/exposure policy explicit.
  • Control failure: repository tests/documentation distinguish the default as "dev only" but do not prove that an accidental use of the profile fails closed or is loopback-contained.
  • Blast radius: local workstations, CI/self-hosted runners, demos, remote Docker hosts, and any deployment that starts the provided Compose file without overriding the credential/exposure defaults.

Current primary evidence

Docker's official PostgreSQL image supports Docker secrets for initialization through POSTGRES_PASSWORD_FILE=/run/secrets/<name> instead of embedding a password value in Compose configuration. The Docker documentation also states that published ports are available on host network addresses unless a localhost bind address is specified; internal Compose service communication does not require host publication.

Primary documentation to reverify at implementation time:

Distinct remedies / feasibility

  1. Preferred for the checked-in local profile: remove the shared password fallback and require an explicit development secret, ideally through a file/secret contract where supported. Keep the database reachable to sibling services over the Compose network without publishing database ports by default.
  2. Acceptable explicit developer override: if host SQL access is a supported local-development use case, place host publication in an opt-in development override/profile and bind it to loopback (127.0.0.1) rather than all host interfaces. The password must still be explicit rather than a repository-known fallback.
  3. Alternative: generate a random ephemeral local credential through a repository-owned setup command only if generation, propagation to all dependent services, persistence/restart semantics, cleanup, and secret-safe output are deterministic and testable. Do not silently regenerate credentials against an existing volume.
  4. Reject: retain xtrmetl because the file says "development only"; prose cannot constrain executable deployment.
  5. Reject: replace the fallback with another constant or encode a credential in a committed .env file.
  6. Reject: remove authentication by enabling PostgreSQL trust authentication to simplify local startup.

TDD / acceptance

After the Compose writer lane is clear, add fail-first tests at the deployable topology boundary. Final acceptance must prove:

  1. the checked-in default profile contains no known fallback for POSTGRES_PASSWORD, REPLICA_POSTGRES_PASSWORD, PGPASSWORD, or REPLICA_PGPASSWORD;
  2. starting the profile without required credential authority fails deterministically before a database with a known password is exposed;
  3. ETL/CDC receive the same approved credential contract without copying secret values into source, logs, metrics, traces, PR text, or generated documentation;
  4. PostgreSQL is not host-published by default unless the supported local profile explicitly requires it;
  5. any opt-in host database mapping is loopback-bound and documented as development-only;
  6. sibling services still connect over the Compose network without relying on host-published ports;
  7. existing persistent-volume behavior is documented so changing the environment variable does not falsely imply that an already initialized PostgreSQL password changed automatically;
  8. clean-install and existing-volume upgrade/recovery cases are both tested;
  9. backup/restore/operator guidance explains credential rotation and lost-secret recovery without destructive reset of customer data;
  10. Security/Threat Model/Operability/Deployment/Traceability and canonical docs reconcile the final profile when docs: establish canonical commercial architecture baseline #149/[Documentation] Close canonical architecture coverage and live traceability gaps #159 is safe;
  11. current CI/dependency/SBOM/SAST/security, non-vacuous coverage, and independent review gates pass on the exact candidate before protected integration.

Standalone / MSA and compliance boundary

Standalone ETL/CDC operation must remain possible with an explicitly supplied database credential. A composed MSA may use deployment-specific secret stores, but mightyETL must not require a ContextualWisdomLab central service merely to obtain a local database password. This is consistent with least privilege and purpose-bound secret handling relevant to SOC 2/CSAP evidence without claiming certification from source code alone.

Do not solve this by blanket data masking; business data remains usable while credential authority and network exposure are tightened.

References (APA 7)

Docker. (2026). PostgreSQL Docker Official Image: Docker secrets. https://github.com/docker-library/docs/blob/master/postgres/README.md

Docker. (2026). Port publishing and mapping. https://docs.docker.com/engine/network/port-publishing/

Docker. (2026). Compose file reference: Services. https://docs.docker.com/reference/compose-file/services/

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionbugSomething isn't workingpriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions