Secrets and Configuration Patterns, Runtime Injection, Environment Risk, Build Secrets, and External Secret Stores: Configuration, Design Choices, and Tradeoffs
Choose among environment variables, mounted files, BuildKit build secrets, Compose secrets, Swarm secrets, and external providers by trust boundary, lifecycle, auditability, and portability.
Learning objectives
- Choose a secret/configuration delivery mechanism based on phase, scope, portability, and trust boundary.
- Distinguish local Compose secrets, Swarm secrets, and external secret-manager integration without treating them as equivalent.
- Compare static and short-lived credentials, file and environment exposure, and build versus runtime authorization.
- Design observable rotation and rollback behavior without exposing credential values.
1. Start with the decision, not the syntax
“How do I pass a variable?” is often the wrong first question. Ask instead: Is the value sensitive? Which phase needs it? Who issues it? Which exact consumer should read it? How long should it remain valid? What evidence proves rotation or revocation? The resulting mechanism becomes much easier to choose.
2. Environment variable versus mounted file versus provider
| Pattern | Strengths | Risks / limits | Good fit |
|---|---|---|---|
| Environment variable | Simple, portable app interface | Broad process/config exposure; easy to print; not a secret store | Non-secret configuration |
| Read-only mounted file | Narrow path, standard filesystem permissions, easy per-service grant | Source storage still needs protection; app must support file reads; rotation semantics vary | Local Compose secret-compatible runtime injection |
| External provider API/agent | Central policy, short leases, audit, revocation, rotation | Bootstrap identity, network/provider availability, SDK/agent complexity | Production runtime secrets across hosts |
| BuildKit secret/SSH mount | Ephemeral build-step exposure, absent from final image by design | Builder is still trusted; build command can deliberately leak it | Private dependencies, signing/fetch auth during build |
3. Build secret versus runtime secret
A dependency-download credential can disappear when the image is finished. A database password is meaningless during image construction and must exist when the application runs. Putting a runtime credential into the build makes every image copy a secret-delivery event; putting a build credential into runtime broadens authority after it is needed.
Use different identities where possible. A package-reader token should not also be a production database administrator token.
4. Static versus short-lived credentials
Static credentials are operationally simple but create long exposure windows. Short-lived credentials reduce the useful lifetime of a leak, especially when the issuer can bind them to an audience, role, workload, or repository. They also demand reliable refresh and clock/provider availability.
A rotation design needs versioned evidence: issuance time, active version, consumer reconciliation time, old-version revocation, and validation that the workload still functions. “We changed the file” is not enough.
5. Compose, Swarm, and external providers are different trust models
Local Compose: a source such as a local file is granted to selected services and mounted as a file. This improves service-level scope but does not turn the local source into encrypted secret storage.
Swarm: the orchestrator manages secret distribution for services. This is relevant to Swarm estates, not a reason to initialize Swarm merely to get a secret API for a local lab.
External manager: a separate security system owns secret material and authorization. Docker usually transports only the workload bootstrap identity, mounted result, or provider integration—not the provider’s policy model itself.
6. Decision table
| Scenario | Preferred design | Prerequisites | Evidence |
|---|---|---|---|
| Private package fetch during build | BuildKit secret or SSH mount | BuildKit frontend/support; dedicated read-only credential | Build trace, image/history search, successful failure when secret omitted |
| Local app password in Compose lab | Per-service Compose secret file | Linux-container secret support; protected source file | Normalized model, mount metadata, no password in Config.Env/logs |
| Production rotating database credential | External provider or platform-native secret service | Workload identity, provider availability, rotation client behavior | Provider audit/version, workload refresh, revocation result |
| Feature flag / log level | Ordinary config via environment/file | No confidentiality requirement | Rendered config and container config |
7. Rollback is identity-aware
Rolling an application image back by digest does not necessarily roll a secret back. That separation is usually good: credentials can rotate independently. But it means incident procedures must define whether an old binary is compatible with the current secret format/provider policy. Record image identity and secret-version identity separately.
8. Performance and reliability tradeoffs
Environment reads and mounted files are local and cheap. Provider API calls introduce network latency and failure modes; caching reduces latency but creates another secret-retention surface. Choose a TTL aligned with credential lifetime and outage tolerance, and never solve provider latency by baking a long-lived secret into an image.
Knowledge check
When is an environment variable appropriate?
For ordinary non-secret configuration whose inspect/log/process exposure is acceptable and whose lifecycle matches container configuration. It is not the preferred secret transport.
How do local Compose secrets differ from Swarm secrets?
Local Compose grants a source-backed file to selected services; it does not automatically provide Swarm’s orchestrator-managed encrypted secret store. The same YAML word “secret” does not mean identical storage or threat boundaries.
Why are short-lived credentials valuable?
They reduce the useful lifetime of a leaked credential and enable policy systems to issue narrowly scoped access, but rotation/revocation and workload refresh still need explicit engineering.
What is the safest default for an external secret manager integration?
Authenticate the workload with the narrowest bootstrap identity available, fetch only the required secret, avoid persisting the value, constrain cache/lifetime, and preserve provider-side audit/revocation evidence without logging the secret.
Why separate configuration from secrets?
Configuration benefits from visibility and reproducibility; secrets require restricted distribution and rotation. Treating them identically either hides useful configuration or overexposes credentials.
Official references and version notes
- Docker Build secrets — secret mounts, SSH mounts, Git authentication secrets, file/environment sources, and build-time scope.
-
Dockerfile reference
—
RUN --mount=type=secret,RUN --mount=type=ssh,required, target, ownership, and environment exposure options. -
SecretsUsedInArgOrEnv build check
— why Dockerfile
ARG/ENVare not secret channels. - Manage secrets securely in Docker Compose — per-service grants and file-based runtime delivery.
- Compose secrets reference — top-level secret definitions and service consumption.
- Compose environment-variable best practices — configuration precedence and why sensitive data should use secrets.
- Swarm secrets — orchestrator-managed secret semantics, intentionally distinct from local Compose file mounts.
- Docker Engine 29 release notes — current Engine baseline.
- Buildx releases and BuildKit releases — current builder/frontend assumptions.
Docker Engine 29.8.1 is the current Engine release; Buildx 0.37.1 and BuildKit 0.33.0 are the current upstream baselines used for feature notes; Compose v5.5.1 is the current Compose release. Docker documents build arguments and Dockerfile environment variables as inappropriate for secrets because sensitive values can persist in image metadata/history, while BuildKit secret/SSH mounts expose credentials only to the build step. Compose secrets are granted per service and delivered as files (on Linux, local Compose uses a single-file bind mount); that is not the same storage/trust model as Swarm secrets or an external secret manager. Labs therefore record the actually installed Engine, Buildx, BuildKit, Compose, context, platform, and secret-delivery path before drawing conclusions.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.