# aws-actions/amazon-ecr-login: outputs named after the registry, public ECR and other accounts

> Use aws-actions/amazon-ecr-login v2: its inputs and outputs, private vs public ECR, cross-account registries and passing the login to other jobs.

Source: https://latchkey.dev/learn/actions/aws-actions-amazon-ecr-login  
Updated: 2026-11-12

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`.

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](/learn/docker/docker-ecr-repository-does-not-exist-create) failure. A post step logs out of every registry it logged in to.

```.github/workflows/push.yml
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.

```.github/workflows/push.yml
- 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}]'`.

```.github/workflows/push.yml
- 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`.

## References

- [aws-actions/amazon-ecr-login README and action.yml at v2.1.7 (read 2026-11-12)](https://github.com/aws-actions/amazon-ecr-login/blob/v2.1.7/README.md)
- [amazon-ecr-login index.js at v2.1.7](https://github.com/aws-actions/amazon-ecr-login/blob/v2.1.7/index.js)
- [Amazon ECR: private registry authentication](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html)
- [Issue #546: passing ECR credentials to another job does not work](https://github.com/aws-actions/amazon-ecr-login/issues/546)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
