Authenticating to Registries Securely in Workflows
The most secure registry credential is the one you never store -- short-lived tokens minted per run beat long-lived secrets.
Registry credentials are a prime target, and a leaked one can let an attacker publish malicious images. This lesson covers authenticating safely, favoring short-lived and keyless approaches over static secrets.
Prefer short-lived over static credentials
A long-lived password or personal access token stored as a secret is a standing risk. The built-in GITHUB_TOKEN is minted per run and expires when the job ends, which is far safer for pushing to GHCR.
Use OIDC for cloud registries
For ECR or GAR, OpenID Connect lets the workflow exchange a signed identity token for short-lived cloud credentials -- no static keys stored at all.
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/ci-ecr-push
aws-region: us-east-1
- uses: aws-actions/amazon-ecr-login@v2Apply least privilege
- Grant packages: write only on jobs that actually push.
- Scope tokens to a single repository or registry path, not your whole account.
- Never echo or log a token; pipe it via --password-stdin.
- Avoid exposing registry secrets to pull_request workflows from forks.
Rotate and audit
If you must use a static credential, store it as an encrypted secret, rotate it on a schedule, and audit registry access logs. But treat that as a fallback -- per-run tokens and OIDC remove the secret from the equation entirely.
Key takeaways
- Prefer per-run tokens (GITHUB_TOKEN) and OIDC over stored static credentials.
- OIDC exchanges a signed identity for short-lived cloud credentials with no stored keys.
- Apply least privilege: scope write access to the jobs and paths that need it.