skip to content

In an ECS task definition, what is the difference between putting a value in a container's `environment` list and its `secrets` list, and what happens to an already-running task when the referenced secret is rotated?

level: middleimportance: nice to knowfreq 34%

answer

  1. one stores the value, one stores an ARN
  2. who can describe the definition
  3. execution role, not task role
  4. resolved once, at launch
  5. rotation needs a redeploy or an SDK read

basics

~20 s

An environment entry stores the literal value in the task definition, visible to anyone who can describe it. A secrets entry stores only an ARN, and the agent resolves it at task start using the task execution role. Rotation does not reach running tasks; they keep the value injected at launch.

solid answer

~50 s

Both end up as environment variables inside the container, so the difference is not runtime — it is what the task definition itself contains. An `environment` entry is `{name, value}` with the literal string, and a task definition is readable by anyone with `ecs:DescribeTaskDefinition`, is versioned forever, and often lives in source control. A `secrets` entry is `{name, valueFrom}` where `valueFrom` is the ARN of a Secrets Manager secret or an SSM parameter; the ECS agent resolves it when the task starts, using the **task execution role** rather than the task role, and injects the resolved value into the container's environment. So the plaintext never sits in the definition. The catch is that resolution happens exactly once, at launch. Rotating the secret afterwards changes nothing for running tasks — they hold whatever was injected until a new deployment replaces them, which is why long-running services usually read through the SDK with a cache instead.

go deeper

for a junior

Know that ECS can inject a secret into a container instead of writing the value into the task definition, and that the definition should never contain a password in its environment list.

for a middle

Explain that valueFrom holds an ARN resolved at task start by the task execution role, that both forms end up as environment variables, and that injection happens once with no refresh on rotation.

for a senior

Show the operational consequence: after a rotation the fleet is split between tasks that work and tasks that do not, and say when you would force a new deployment versus move the read into the application with a cache and retry.

for a principal

Own the standard for the estate — which consumption pattern is mandated for which rotation cadence, how execution-role permissions are scoped per service rather than shared, and how rotation is validated end to end rather than declared.

## Two ways to get a value into a container An ECS container definition can populate environment variables two ways: ```json "environment": [ { "name": "LOG_LEVEL", "value": "info" } ], "secrets": [ { "name": "DB_PASSWORD", "valueFrom": "arn:aws:secretsmanager:eu-west-1:111122223333:secret:prod/db-AbCdEf" } ] ``` Inside the container both appear identically — `LOG_LEVEL` and `DB_PASSWORD` are both environment variables. The difference is entirely about where the value lives before the container starts. ## What `environment` costs you The literal string is part of the task definition document. That has consequences people underestimate: - **It is readable.** `ecs:DescribeTaskDefinition` is a common, low-suspicion permission, frequently granted broadly for deployment tooling and dashboards. Anyone holding it reads the value. - **It is immortal.** Task definitions are immutable revisions and old revisions are retained. A password committed in revision 12 stays readable long after revision 40 removed it, unless the revision is explicitly deregistered and deleted. - **It usually lives in source control**, because the definition is generated from a template checked into a repository. So `environment` is right for configuration — log levels, feature flags, endpoints — and wrong for anything you would not paste into a pull request. ## What `secrets` does A `secrets` entry stores only a reference. `valueFrom` accepts the ARN of a Secrets Manager secret or of an SSM Parameter Store parameter, and for Secrets Manager it can address a single JSON key and a version — the ARN can be suffixed with the JSON key name, the version stage and the version id — so one secret holding a JSON credential blob can populate several distinct environment variables. At task launch the ECS agent resolves each reference and injects the result. Two authorization points matter, and mixing them up is the standard failure: - The **task execution role** is what resolves the secret. It is the role ECS itself assumes to pull the image, write logs and fetch secrets, and it is the one that needs `secretsmanager:GetSecretValue` or `ssm:GetParameters`, plus `kms:Decrypt` when a customer managed key is involved. - The **task role** is what the application's own SDK calls use at runtime, and it is irrelevant to injection. Grant the permission to the task role by mistake and the task fails to start with a ResourceInitializationError before your code runs at all — which is at least a loud failure rather than a silent one. A parallel mechanism exists for the log driver: `logConfiguration.secretOptions` takes the same `{name, valueFrom}` shape, so a third-party log destination's API key is not in the definition either. ## The rotation gap Resolution happens once, at task start. There is no watcher, no refresh, no signal into the running container. If the secret rotates ten minutes later, every running task still holds the previous value, and will until something replaces the task — a new deployment, a scale-out that starts fresh tasks, a health-check failure that recycles one. That produces a specific and confusing incident shape: after a rotation, *newly started* tasks work and old ones fail, so the service is partially broken in proportion to how recently each task launched. It also means "we rotate our database password automatically" is only half true if consumption is by injection — the rotation succeeds and the fleet keeps using the old credential. The options, in increasing order of effort: 1. **Accept it** for values that rotate rarely, and make rotation a deployment: rotate, then force a new deployment (`aws ecs update-service --force-new-deployment`) so tasks pick up the new value. Simple, and adequate for a quarterly rotation. 2. **Read through the SDK** in the application with an in-process cache and refetch on authentication failure. The task role needs the read permission, and the value is never in the environment at all — which also keeps it out of anything that dumps the process environment into a crash report. 3. **Use alternating-users rotation** so the injected credential stays valid until the next deployment, buying time for option 1 to be unhurried. ## A limit worth naming Injection puts the value in the process environment, which is a slightly weaker resting place than a variable your code fetched: the environment is visible to every process in the container, is captured by many crash and diagnostic tools, and is inherited by child processes. `secrets` fixes the *task definition* exposure, not the *process environment* exposure. For most services that tradeoff is entirely reasonable — the point is to be able to say which problem you solved.

  • A task fails to start with a ResourceInitializationError mentioning the secret. Where do you look?
    At the **task execution role**, not the task role. ECS resolves `valueFrom` before the container runs, using the execution role, so it needs `secretsmanager:GetSecretValue` (or `ssm:GetParameters`) on that ARN plus `kms:Decrypt` when a customer managed key encrypts it. Also confirm the ARN is complete — Secrets Manager ARNs carry a random suffix that is easy to truncate in a template.
  • How do you make a rotated secret reach a running ECS service?
    Replace the tasks. The usual path is to rotate and then run `aws ecs update-service --force-new-deployment`, so fresh tasks resolve the new value while the old ones drain. If that coupling is unacceptable, stop injecting and have the application read the secret through the SDK with a bounded cache and a refetch on authentication failure.
  • Can one Secrets Manager secret populate several environment variables in an ECS container?
    Yes. For a secret whose value is a JSON document, the `valueFrom` ARN can name a specific JSON key, so you write one `secrets` entry per variable — username to one, password to another — all pointing at the same secret. That keeps a credential pair together as a single rotatable unit while still arriving as separate variables.

saying these in an interview costs you the question

  • Putting the password in `environment` because it is encrypted at rest anyway
  • Granting the secret read permission to the task role instead of the execution role
  • Assuming ECS refreshes injected secrets when the source rotates
  • Thinking `secrets` keeps the value out of the process environment
  • Treating old task definition revisions as deleted once a new one is registered

context