Access OCI Helm charts in private Amazon ECR
Configure Harness GitOps to pull OCI Helm charts from a private Amazon ECR registry using IRSA or External Secrets Operator.
This topic assumes you have already created an OCI Helm repository.
Amazon ECR issues short-lived authentication tokens that expire after 12 hours. To pull OCI Helm charts from a private ECR registry, the Argo CD repo server must authenticate to ECR continuously. There are two approaches:
IRSA (recommended): Attach an IAM role with ECR permissions directly to the
argocd-repo-serverservice account using IAM Roles for Service Accounts. The repo server uses AWS IAM APIs to authenticate natively, with no stored credentials or token rotation required.External Secrets Operator (ESO): Install ESO in the cluster and configure it to rotate the ECR token in the Kubernetes secret that stores the repository credentials.
Use IRSA when your GitOps Agent runs on Amazon EKS. Use ESO when IRSA is not available (for example, self-managed Kubernetes clusters outside of EKS).
Option 1: Use IRSA (recommended)
With IRSA, the argocd-repo-server pod assumes an IAM role through the EKS OIDC provider. The repo server authenticates to ECR using the AWS SDK, so you do not need to store or rotate any credentials.
Prerequisites
Amazon EKS cluster: The GitOps Agent must run on an EKS cluster with an OIDC provider enabled.
OCI Helm repository: An OCI Helm repository already added in Harness GitOps. Go to Add a Harness GitOps repository to set one up.
Create an IAM role with ECR permissions
Create an IAM policy that grants read access to your ECR repositories:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer", "ecr:BatchCheckLayerAvailability" ], "Resource": "arn:aws:ecr:<REGION>:<ACCOUNT_ID>:repository/<REPOSITORY_NAME>" } ] }Replace
<REGION>,<ACCOUNT_ID>, and<REPOSITORY_NAME>with your values. To grant access to all repositories in the account, usearn:aws:ecr:<REGION>:<ACCOUNT_ID>:repository/*.Create an IAM role and attach the policy from the previous step. Configure the trust policy to allow the
argocd-repo-serverservice account to assume the role:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>:sub": "system:serviceaccount:<AGENT_NAMESPACE>:argocd-repo-server", "oidc.eks.<REGION>.amazonaws.com/id/<OIDC_ID>:aud": "sts.amazonaws.com" } } } ] }Replace
<ACCOUNT_ID>,<REGION>,<OIDC_ID>, and<AGENT_NAMESPACE>with your values.
Annotate the repo server service account
Annotate the argocd-repo-server service account with the IAM role ARN:
Enable service account token mounting
Ensure automountServiceAccountToken is set to true on the repo server deployment so the projected service account token is available to the AWS SDK:
Restart the repo server
Restart the repo server deployment to pick up the new service account annotation and token:
After the pods restart, the repo server authenticates to ECR automatically using the assumed IAM role. You do not need to provide a username, password, or token when you add the ECR repository in Harness.
Option 2: Use External Secrets Operator
If IRSA is not available, use the External Secrets Operator to rotate ECR tokens automatically. ESO fetches a fresh token from ECR at a configured interval and updates the Kubernetes secret that stores the repository credentials.
Install External Secrets Operator
Install ESO in the cluster where Argo CD is running:
This installs ESO with the ClusterSecretStore, ExternalSecret, and ECRAuthorizationToken CRDs. The ECRAuthorizationToken generator produces a fresh ECR token on demand.
Create AWS credentials in a Kubernetes secret
Create a Kubernetes secret that contains AWS access credentials. ESO uses these credentials to call the ECR GetAuthorizationToken API.
Replace <AWS_ACCESS_KEY_ID> and <AWS_SECRET_ACCESS_KEY> with your actual credentials.
Create the ECR token generator
Create a file named generator.yaml with the following content:
Replace <REGION> with the AWS region of your ECR registry (for example, us-west-1).
Apply the generator:
Create the ExternalSecret
Identify the Kubernetes secret that stores your OCI Helm repository credentials. List the repo secrets in the Argo CD namespace:
Inspect the target secret to confirm it corresponds to your ECR repository:
Create a file named external-secret.yaml. Replace the placeholder values before applying:
REPO_SECRET_NAME: the Kubernetes secret name for your repository (for example,repo-2529854065).
In the template.data.password field, use the Go template expression "{{ .password }}" to inject the rotated password into the secret.
Set the password value under template.data to the Go template expression shown above. This injects the ECR token fetched by the generator into the repository secret.
Apply the ExternalSecret:
Key fields in the ExternalSecret:
refreshInterval: How often ESO fetches a new ECR token. ECR tokens expire after 12 hours, so12hor shorter is recommended.creationPolicy: Merge: ESO merges the newpasswordfield into the existing secret rather than recreating it. This preserves the other fields (URL, type, enableOCI) that Argo CD requires.generatorRef: Points to theECRAuthorizationTokengenerator created in the previous step.
Last updated
Was this helpful?