aws-actions/amazon-ecr-login calls ECR's GetAuthorizationToken with whatever AWS credentials the job already has, then runs docker login against the registry, so later docker push and build-push-action steps are authenticated. It does not mint AWS credentials itself: aws-actions/configure-aws-credentials supplies them, and the login needs only ecr:GetAuthorizationToken.

What the action calls, what it outputs and what the other side must allow, for each of the three ways to use it.
The login step is three lines in most workflows, which is why its edges surprise people: outputs named after the registry host, a password that will not cross to another job, a registry output that is sometimes empty, and a public registry that authenticates in a region you never chose.
Most of them follow from how little the action does: it calls GetAuthorizationToken with credentials an earlier step set, runs docker login, and everything else depends on where those credentials point. Inputs and behavior are from action.yml, the README and index.js at v2.1.7, read 2026-11-12.
The usual pairing: credentials, login, build and push
configure-aws-credentials exports the session and AWS_REGION. The login step reads explicit environment credentials first, then EKS Pod Identity, then the SDK's default chain, and asks ECR for a token in that region. The token decodes to the username AWS and a password, and AWS documents it as valid for 12 hours for any registry the principal can reach.
The registry output is the host, 123456789012.dkr.ecr.us-east-1.amazonaws.com, which is what you prefix tags with. The repository must already exist; ECR does not create one on push unless a repository creation template matches, which is the repository does not exist failure. A post step logs out of every registry it logged in to.
permissions: id-token: write contents: read jobs: push: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0 with: role-to-assume: arn:aws:iam::123456789012:role/ecr-push aws-region: us-east-1 - id: ecr uses: aws-actions/amazon-ecr-login@03f1aad4c6c7ffd436567f42f9384779290529bd # v2.1.7 - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: . push: true tags: ${{ steps.ecr.outputs.registry }}/my-app:${{ github.sha }} Outputs named after the registry host
Five inputs, all optional. The credential outputs are named after the registry host with every run of characters outside [a-zA-Z0-9_] replaced by one underscore, so the names change with the account and region.
| Name | Kind | Default | Notes |
|---|---|---|---|
registries | input | the default private registry | Comma-separated 12-digit account IDs; ignored for public |
registry-type | input | private | private or public |
mask-password | input | true (since v2) | A masked password cannot be a job output |
skip-logout | input | false | Keeps the login after the job; the README calls it not recommended |
http-proxy | input | none | HTTP_PROXY in the environment is also honored |
registry | output | The registry host; not set when several registries are logged in | |
docker_username_<host> | output | For example docker_username_123456789012_dkr_ecr_us_east_1_amazonaws_com | |
docker_password_<host> | output | Same naming; ECR Public uses docker_password_public_ecr_aws |
Private and public ECR
Private is the default: the token comes from the ecr API in your configured region, and the role needs ecr:GetAuthorizationToken on * plus repository-scoped actions to push (ecr:BatchCheckLayerAvailability, ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:PutImage) or pull (ecr:BatchGetImage, ecr:GetDownloadUrlForLayer).
Public needs registry-type: public. The source pins the ECR Public client to us-east-1 with the comment that authentication there only works in that region, whatever aws-region you set. The login needs ecr-public:GetAuthorizationToken and sts:GetServiceBearerToken, the registry is public.ecr.aws, and image paths include your registry alias. Pulling public images needs no login at all.
- id: ecr-public uses: aws-actions/amazon-ecr-login@03f1aad4c6c7ffd436567f42f9384779290529bd # v2.1.7 with: registry-type: public - run: | docker build -t "$REGISTRY/my-alias/my-app:$GITHUB_SHA" . docker push "$REGISTRY/my-alias/my-app:$GITHUB_SHA" env: REGISTRY: ${{ steps.ecr-public.outputs.registry }} Registries in other accounts
List the account IDs in registries and the action requests a token covering each and logs in to every endpoint returned. Two things change. The registry output is no longer set, so build the hostnames yourself. And the repository in the other account must grant your role access in its repository policy; your own role's IAM policy is not enough on its side.
GitHub reads an input made only of digits as a number, so a single ID that starts with 0 loses it. Quote it. A malformed ID fails with Invalid parameter at 'registryIds' failed to satisfy constraint: 'Member must satisfy constraint: [Member must satisfy regular expression pattern: [0-9]{12}]'.
- id: ecr uses: aws-actions/amazon-ecr-login@03f1aad4c6c7ffd436567f42f9384779290529bd # v2.1.7 with: registries: "123456789012,098765432109" - run: docker pull 098765432109.dkr.ecr.us-east-1.amazonaws.com/base:latest Masking the password, and passing it to another job
v2 changed mask-password from false to true, so the password is registered as a secret and stays out of debug logs. The side effect is deliberate: the runner refuses to pass a job output that contains a secret and warns Skip output 'docker_password' since it may contain secret., so the services: pattern in the README, where one job logs in and another uses the credentials for a private service image, needs mask-password: 'false'.
The registry output carries the account ID, and if configure-aws-credentials masks it (mask-aws-account-id: true) that output is skipped the same way. Prefer logging in again inside the job that needs the image. Pass credentials between jobs only for services: or container: images, which are pulled before any step runs.
| Symptom | Where it comes from | What to check |
|---|---|---|
Skip output 'docker_password' since it may contain secret. | The runner | mask-password: 'false' if the output must cross jobs |
Could not login to registry <host>: ... | The action, wrapping docker login stderr | Docker on the runner and the network path to the registry |
no basic auth credentials on push | Docker | A login for that exact host; issue #337 reports it intermittently on self-hosted runners |
name unknown on push | ECR | The repository name, account and region in the tag |
The runner warning is in actions/runner src/Runner.Worker/JobExtension.cs and is reported against this action in issue #546; the login error is from index.js at v2.1.7. Read 2026-11-12.
FAQ
Why are the amazon-ecr-login outputs empty in my next job?
The runner drops any job output that contains a registered secret and logs "Skip output ... since it may contain secret." Since v2 the password is masked by default. Set mask-password: 'false' only when another job truly needs it, for example a private services: image; otherwise log in again in that job.
How do I log in to ECR in another AWS account from GitHub Actions?
Pass both account IDs in registries, quoted, and grant your role pull or push access in the other repository's policy. The action logs in to each registry, but leaves the registry output unset, so write the hostnames out in your tags.
Do I still need docker/login-action with amazon-ecr-login?
No. amazon-ecr-login runs docker login itself, and build-push-action, docker push and Helm use the same credential store. docker/login-action can also log in to ECR, with access keys or with the credentials configure-aws-credentials exported, so use one of the two login steps, not both.
Why does my push fail with no basic auth credentials after amazon-ecr-login succeeded?
Docker has no login for the host in the tag. Check the tag uses steps.<id>.outputs.registry and the same account and region you logged in to. Issue #337 also reports it intermittently on self-hosted runners, where a commenter resolved it with skip-logout: true.


