Two Ways to Get Secrets Into a Container

  • 22 Feb, 2026

Every containerized app needs real credentials at some point: database passwords, API keys, tokens for whatever third-party service you’re calling. The question is never whether your app needs them. It’s when and how it gets them, and that turns out to have two genuinely different answers, not one obviously correct one.

The problem

A Docker image is meant to be portable. You build it once and the same image can run locally, in staging, in production. That only works if the image itself doesn’t know anything environment-specific, including credentials. So secrets can’t be baked in at build time. They have to arrive some other way, after the container starts, in whatever environment it’s actually running in.

There are two main shapes that answer can take.

Option one: fetch everything once, at startup

One approach is to store a single secret per environment: a JSON blob containing every credential the app needs, as key-value pairs. Basically the same shape as a .env file. When the container starts, an entrypoint script fetches that blob with one API call and exports every key inside it as a real environment variable, before the app itself even launches. From then on, the app just reads config the normal way, getenv('TWILIO_SECRET') or whatever your framework calls it. It has no idea any of this happened.

This is easy to reason about and easy to build. One API call at boot, one place to look when you need to add a new variable, and local development ends up looking almost identical to production, since both are just “environment variables” from the app’s point of view.

But it comes with real costs:

  • You fetch the whole blob even if the app only needs three of the twenty keys in it.
  • Access control and rotation happen at the secret level, not the key level: anything that can read the secret gets every key in it, and most rotation tooling expects one secret per credential, not twenty bundled together.
  • Once the container starts, the actual values sit in the process environment for the container’s whole life. Anything that can read that process’s environment can read every secret, and it’s easy to accidentally leak one into a log line or an error trace if you’re not careful about what you print.

Option two: fetch on demand, per key

The alternative is to not resolve secrets at startup at all. Instead of an environment variable holding the actual value, it holds a reference: a secret name, an ARN, a path. Something like TWILIO_SECRET_REF=projects/x/secrets/twilio-token instead of TWILIO_SECRET=the-actual-token. The real value only gets fetched at the moment something actually needs it, either because the app calls the secrets API directly, or because the platform resolves it on the way in.

Some platforms support this natively. AWS ECS and Fargate, for example, let you point a container’s secrets field at entries in Secrets Manager or Parameter Store directly, and the platform injects the resolved value at launch without the app ever calling an API itself. Other setups use a sidecar, something like a Vault Agent running alongside the app, whose whole job is fetching and refreshing secrets and handing them to the main process.

This buys real things: each secret can be rotated and audited on its own instead of as part of one big blob, access can be scoped per secret instead of per environment, and depending on the implementation, the actual value might never sit in a plain environment variable at all.

It also costs something: the app or platform now has a runtime dependency on the secrets API being reachable, not just at boot but potentially every time a value is needed. One more thing that can fail, one more thing to reason about when something breaks.

What’s actually being traded off

Strip away the mechanics and it’s the same tradeoff that shows up everywhere in infrastructure: precision versus complexity. Bulk-fetch-at-startup is simple enough for a small team to understand in one sitting, and it’s the one I reach for most on personal projects. Per-key resolution is more precise and more auditable, at the cost of being one more moving part that can fail.

Neither is correct in the abstract. What matters is what’s actually true about your team, your scale, and what you’re accountable for, not which pattern is theoretically better.