> For the complete documentation index, see [llms.txt](https://docs.sealsecurity.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealsecurity.io/setup-containers/seal-my-container/authenticating-registry.md).

# Authenticating with your container registry

`seal image fix` invokes `docker pull` against the source image and `docker push` against the sealed result. Both authenticate through the host's standard Docker credential storage; the CLI does not have its own registry-credential mechanism. The setup is exactly the same as for any other Docker-based pipeline that pulls and pushes images.

The canonical pattern uses one registry for both: pull from `your-registry/your-app:1.2.3`, push back to `your-registry/your-app:1.2.3`. One `docker login` covers both halves.

## What you need

* **Registry credentials** with read and write access to the repository holding the image. Whatever registry your team already uses (Docker Hub, AWS ECR, GCP Artifact Registry, Azure Container Registry, GitHub Container Registry, JFrog Artifactory, Harbor, Sonatype Nexus, your own self-hosted Distribution registry).
* Docker installed on the host. `seal image fix` invokes the `docker` binary directly and uses BuildKit's `--secret` for token passing; BuildKit is the default in current Docker releases.

## Logging in for one host

For a developer workstation or a CI agent that runs the seal step directly, log in with the normal `docker login` command:

```bash
docker login <your-registry>
```

`docker login` writes the credentials to `~/.docker/config.json`. The `seal image fix` process inherits the same credential file and uses the same credentials for both its pull (against the source image) and its push (back to the same tag, or to whatever `--tag` overrides to).

If your source and destination are different registries (an unusual setup, used when you specifically want sealed images to land somewhere different from where the unsealed source lives), log in to both.

## In CI

CI systems have built-in registry-login steps that wrap the `docker login` invocation. Use them in preference to running `docker login` directly with passwords in shell variables.

{% tabs %}
{% tab title="GitHub Actions" %}

```yaml
- name: Log in to the registry
  uses: docker/login-action@v3
  with:
    registry: <your-registry>
    username: ${{ secrets.REGISTRY_USERNAME }}
    password: ${{ secrets.REGISTRY_PASSWORD }}
```

For AWS ECR specifically, replace the username/password pair with the [`aws-actions/amazon-ecr-login`](https://github.com/aws-actions/amazon-ecr-login) action.
{% endtab %}

{% tab title="GitLab CI" %}

```yaml
seal-image:
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login "$REGISTRY" -u "$REGISTRY_USERNAME" -p "$REGISTRY_PASSWORD"
```

Configure the username and password variables as masked, protected GitLab CI/CD variables.
{% endtab %}

{% tab title="Jenkins" %}

```groovy
pipeline {
  agent any
  environment {
    REGISTRY = credentials('registry-credentials')
  }
  stages {
    stage('Log in') {
      steps {
        sh '''
          echo "$REGISTRY_PSW" | docker login <your-registry> -u "$REGISTRY_USR" --password-stdin
        '''
      }
    }
  }
}
```

{% endtab %}
{% endtabs %}

## Cloud-provider registries

The cloud-provider registries (ECR, GCP Artifact Registry, ACR) have IAM-bound credentials that rotate frequently. The standard pattern is to delegate authentication to the cloud's CLI:

* **AWS ECR**: `aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com`. In GitHub Actions, the [`amazon-ecr-login`](https://github.com/aws-actions/amazon-ecr-login) action wraps this.
* **GCP Artifact Registry**: `gcloud auth configure-docker <region>-docker.pkg.dev`. The Docker daemon delegates authentication to `gcloud` automatically.
* **Azure Container Registry**: `az acr login --name <registry>` (or, in CI, [`docker/login-action`](https://github.com/docker/login-action) with the registry hostname).

In all three cases, the CI runner's IAM identity needs read and write on the repository holding the image before the login command can produce valid credentials.

## Verifying authentication

A quick smoke test before the first real `seal image fix` run:

```bash
docker pull <your-registry>/<repo>:<tag>
docker push <your-registry>/<repo>:smoke-test
```

If both succeed without prompting for credentials, Docker has the right credentials cached and `seal image fix` will too. A `denied: requested access to the resource is denied` error from either step is a registry-credential problem, not a Seal problem.

## Related

* [The `seal image fix` command and flags](/setup-containers/seal-my-container/seal-image-fix-reference.md): what the registry credentials are used for.
* [Implementing the centralized re-seal pipeline](/setup-containers/seal-my-container/centralized-pipeline.md): the CI shape that wraps the seal step.
* [Authenticating with Seal's image registry](/setup-containers/seal-base-images/authenticating.md): the corresponding page for Seal Base Images, when the source registry is Seal's. The two are unrelated; Seal Base Images authenticates against Seal's registry, Seal My Container authenticates against yours.
