Cloud Experts Documentation

Automating ECR Pull Secrets on ROSA Using the External Secrets Operator and STS

This content is authored by Red Hat experts, but has not yet been tested on every supported configuration.

This guide has been validated on OpenShift 4.20. Operator CRD names, API versions, and console paths may differ on other versions.

Amazon Elastic Container Registry (ECR) issues short-lived authorization tokens that expire after 12 hours. On Red Hat OpenShift Service on AWS (ROSA), workloads that pull images from private ECR repositories need those tokens refreshed before they expire — otherwise pods fail to start with ImagePullBackOff errors.

The External Secrets Operatorexternal link (opens in new tab) (ESO) solves this by generating and automatically refreshing ECR tokens as Kubernetes dockerconfigjson pull secrets. Combined with AWS STS and IAM Roles for Service Accounts (IRSA), this removes every long-lived credential from the picture.

The External Secrets Operator for Red Hat OpenShift is available in OperatorHub on ROSA and OpenShift. It is the recommended, fully-supported distribution and is the version used throughout this guide. See the Red Hat documentation for details.

This guide covers two approaches — pick the one that fits your operating model.

Approach A — Namespace-scoped pull secret

Each namespace owns its own IAM role, service account, and ESO resources.

  • IAM role: one role per namespace/service account
  • ESO resources: ECRAuthorizationToken + ExternalSecret per namespace
  • Namespace onboarding: team creates resources in their namespace
  • Isolation: strong — each namespace has its own IRSA binding
  • Pros: least-privilege per team; compromise of one role does not affect others
  • Cons: more IAM roles to manage; each team must create ESO resources
  • Best for: multi-tenant clusters, strict isolation

Approach B — Centrally managed with label-based namespace injection

A platform team manages ESO resources once at the cluster level. Namespaces opt in via a label.

  • IAM role: one shared role on the ESO controller
  • ESO resources: ClusterGenerator + ClusterExternalSecret (cluster-scoped)
  • Namespace onboarding: platform admin adds a label to the namespace
  • Isolation: shared — single role covers all labeled namespaces
  • Pros: single setup for the entire cluster; easy onboarding via oc label
  • Cons: broader blast radius — a misconfigured shared role affects all labeled namespaces
  • Best for: platform-managed clusters, central governance

Prerequisites

Validate STS

Confirm your cluster is configured with STS before proceeding:

You should see an HTTPS URL such as https://oidc.op1.openshiftapps.com/<unique-id>. If the output is empty, see the Red Hat documentation on creating an STS cluster .

Prepare environment variables

Adjust AWS_REGION and ECR_REPOSITORY to match your environment.

Install the External Secrets Operator for Red Hat OpenShift

Option 1: Via the OpenShift Web Console

  1. Navigate to Ecosystem → Software Catalog and search for External Secrets Operator.

  2. Select External Secrets Operator for Red Hat OpenShift and install it with the default settings (all namespaces, automatic approval).

Option 2: Via the CLI

Create the ExternalSecretsConfig operand

The operator manager pod installs, but the ESO controllers will not start until you create an ExternalSecretsConfig CR named cluster. First, wait for the operator CSV to finish installing:

Then create the operand:

Verify the installation

Wait for the operator manager pod to become ready:

After the ExternalSecretsConfig operand is created, the operator deploys the ESO controller pods into the external-secrets namespace. Verify they are running:

You should see three pods in Running state.

Create an ECR repository (optional)

Skip this step if you already have a private ECR repository. If so, make sure the ECR_REPOSITORY variable set in the previous step matches the name of your existing repository.

To push a test image into the new repository so you can validate the pull secret later:


Approach A — Namespace-scoped pull secret

Complete all Prerequisites , Install the External Secrets Operator for Red Hat OpenShift , and Create an ECR repository steps before continuing.

In this model each namespace owns its own IAM role, service account, and ESO resources. This provides the strongest isolation and is the recommended starting point.

A1) Create an IAM policy for ECR token retrieval

ecr:GetAuthorizationToken requires Resource: "*". All other actions are scoped to the specific repository.

A2) Create the application namespace and a dedicated service account

The External Secrets Operator needs a service account annotated with an IAM role to authenticate against AWS via IRSA. A dedicated service account (rather than default) is used so the IAM trust policy grants ECR access only to the ESO generator — not to every pod in the namespace.

A3) Create an IAM role with an IRSA trust policy

The trust policy restricts role assumption to the specific service account and namespace created above.

A4) Attach the policy and annotate the service account

A5) Create an ECR token generator

The ECRAuthorizationToken custom resource tells the External Secrets Operator how to request a token. The serviceAccountRef binds the generator to the IRSA-annotated service account.

A6) Create an ExternalSecret to render the pull secret

The ExternalSecret uses the generator from the previous step and produces a standard kubernetes.io/dockerconfigjson secret that OpenShift can use as an image pull secret. The refreshInterval is set to 11 hours, ensuring the token is always refreshed before the 12-hour expiry window.

A7) Verify the generated secret

The STATUS column should show SecretSynced. Then confirm the Kubernetes secret exists:

Expected output:

By default, OpenShift pods use the default service account. That service account does not automatically know about the newly created pull secret. The oc secrets link --for=pull command adds the secret to the service account’s imagePullSecrets list so the kubelet presents the credentials when pulling images.

If your workloads use a different service account, link the secret to that service account as well.

A9) Validate with a test pod

Watch the pod until it reaches Running:

If the pod starts successfully the entire pipeline — IRSA, token generator, and pull secret — is working correctly.

A10) Cleanup


Approach B — Centrally managed with label-based namespace injection

Complete all Prerequisites , Install the External Secrets Operator for Red Hat OpenShift , and Create an ECR repository steps before continuing.

In this model, a platform team manages ESO resources once at the cluster level. Any namespace that needs ECR pull secrets simply receives a label.

How it works

  1. The ESO controller service account is annotated with a single shared IRSA role.
  2. A ClusterGenerator defines how to obtain ECR tokens cluster-wide.
  3. A ClusterExternalSecret watches for namespaces with a specific label and creates an ExternalSecret (and therefore a pull secret) in each matching namespace automatically.

B1) Create the shared IAM role for the ESO controller

Reuse the same OIDC_ENDPOINT and AWS_ACCOUNT_ID variables from the prerequisites section.

B2) Annotate the ESO controller service account

Restart the operator deployment so it picks up the annotation:

B3) Create a cluster-scoped ECR token generator

The ClusterGenerator wraps the ECRAuthorizationToken spec so it is available across all namespaces without redefining it per team.

B4) Create a ClusterExternalSecret with a namespace label selector

The ClusterExternalSecret acts as a template: for every namespace carrying the label ecr-pull-secret: "true", the operator creates a namespaced ExternalSecret which in turn produces the pull secret.

B5) Onboard namespaces by adding a label

Within a minute the operator will create an ExternalSecret and the resulting ecr-docker-credentials secret in each labeled namespace:

As explained in Approach A, step A8 , linking is required so that pods running under the default service account can use the generated pull secret when pulling images from ECR.

B7) Validate with a test pod

B8) Remove a namespace from ECR pull secret distribution

To stop injecting the secret into a namespace, remove the label:

The trailing - in the label key tells oc label to remove the label.

The operator will delete the ExternalSecret and the generated secret from that namespace.

B9) Cleanup (centrally managed)


Additional resources

Interested in contributing to these docs?

Collaboration drives progress. Help improve our documentation The Red Hat Way.

Red Hat logo LinkedIn YouTube Facebook Twitter

Products

Tools

Try, buy & sell

Communicate

About Red Hat

We’re the world’s leading provider of enterprise open source solutions—including Linux, cloud, container, and Kubernetes. We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Subscribe to our newsletter, Red Hat Shares

Sign up now
© 2026 Red Hat