Registry access
Both the chart and the application images live in a private ECR registry. Access is read-only, scoped to your organisation’s repositories, and granted through an IAM role in Edisyl’s account that a principal in yours is allowed to assume. Nothing is shared: no registry password, no long-lived key.
How access is granted
Section titled “How access is granted”Four steps, alternating sides. The first two happen before you touch a cluster; the last two are what the rest of this page walks through.
- You send Edisyl your AWS account ID and the ARN of the IAM principal that will assume the role — normally your cluster’s node role or an IRSA role; an IAM user also works. It must be a plain IAM role or user, not an SSO assumed-role ARN: our trust policy pins the principal’s unique ID, and SSO roles are recreated whenever their permission set changes.
- Edisyl creates your role and sends back the table below. The
<name>in the role ARN is your client ID. Edisyl assigns it; you do not choose it. The same ID is the prefix your usage archives land under, which is why the configurator asks for it first and derives the role ARN from it everywhere. - You allow the assume on your side — the policy in the next section.
Our trust policy names your principal; your principal still has to be
permitted to call
sts:AssumeRoleon our role. - You configure the pull: a profile for
helm pull, and the chart’s token refresher for the cluster, both further down.
| What Edisyl sends you | |
|---|---|
| Client ID | The <name> in the role ARN below; also your usage-export prefix |
| Role ARN | arn:aws:iam::944311261080:role/edisyl-client-<name> |
| External ID | Not a secret, but required on every assume |
| Registry | 944311261080.dkr.ecr.us-east-1.amazonaws.com |
| Region | us-east-1 |
| Repositories | The chart and the images your role can read |
If you have not received these, ask before going further — nothing below works without them.
Allow the assume on your side
Section titled “Allow the assume on your side”Our trust policy naming your principal is only half of a cross-account assume. Attach this to the principal that will pull — normally your cluster’s node role or an IRSA role:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AssumeEdisylRegistryRole", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::944311261080:role/edisyl-client-<name>" } ]}Without it you get AccessDenied on sts:AssumeRole regardless of what we
allow on our side.
Configure a profile
Section titled “Configure a profile”[profile edisyl-registry]role_arn = arn:aws:iam::944311261080:role/edisyl-client-<name>external_id = <external-id>region = us-east-1
# Where the credentials to assume FROM come from. Pick one:source_profile = <your-profile> # an IAM user's keys# credential_source = Ec2InstanceMetadata # an EC2 instance role# credential_source = EcsContainer # an ECS task rolerole_arn alone is not enough — without source_profile or
credential_source the SDK has nothing to assume from.
If your principal is itself a role, this is role chaining and STS caps the session at one hour. Requesting longer fails.
Log in and pull the chart
Section titled “Log in and pull the chart”aws ecr get-login-password --region us-east-1 --profile edisyl-registry \ | helm registry login --username AWS --password-stdin \ 944311261080.dkr.ecr.us-east-1.amazonaws.com
helm pull oci://944311261080.dkr.ecr.us-east-1.amazonaws.com/edisyl-charts/edisyl-helm \ --version <chart-version>Pick a version from the image matrix. Helm never needs to understand STS — it just receives the password.
Keep the pull secret fresh
Section titled “Keep the pull secret fresh”ECR authorization tokens expire after 12 hours. An imagePullSecret
holding one stops working overnight, and the failure is delayed rather than
immediate: running pods keep running, and the first sign is an
ImagePullBackOff on the next restart, rollout or scale-up — hours after the
cause.
Pick one of the two approaches below. The chart ships the first.
Let the chart refresh it
Section titled “Let the chart refresh it”images: registry: 944311261080.dkr.ecr.us-east-1.amazonaws.com pullSecret: edisyl-ecrecrRefresh: enabled: true region: us-east-1 # Cross-account, which is how Edisyl grants access. Omit both for a # registry in your own account. roleArn: arn:aws:iam::944311261080:role/edisyl-client-<name> externalId: <external-id>The chart then mints a fresh token and rewrites the secret every four hours. Four, not six: with a six-hour schedule a run at midnight, a missed one at 06:00 and the next at noon would land the refresh exactly on the expiry. At four, the same missed run still leaves four hours of margin.
The refresher can read and write only the one secret it maintains — get,
patch and update on that name, with no create verb at all. That matters,
because the same namespace holds your database credentials, the JWT signing
keys and every third-party API key.
Its container image defaults to a public one, deliberately: an image pulled from our registry would mean an expired secret leaves you unable to run the one thing that fixes it.
Seed the secret once first
Section titled “Seed the secret once first”The refresher refreshes and never creates. The initial pull secret is a prerequisite of installing at all, because the pre-install migrate hook pulls a first-party image before anything the chart renders could refresh it. If the secret is missing, the refresher says so rather than failing opaquely.
The chart can create it for you, which is the easier path. Two of the three values are not secret and belong in the file you commit:
images: pullSecret: edisyl-ecr # the NAME of the secret to create pullSecretAuth: enabled: true username: AWS # always AWS for ECRThe password is an ECR authorization token, not your role ARN and not a
long-lived key. You mint one with the profile configured above — which is where
the role and external ID live — and hand it to helm on the command line:
helm install edisyl <chart> -n edisyl \ -f edisyl.values.yaml -f secrets.local.yaml \ --set-string images.pullSecretAuth.password="$(aws ecr get-login-password \ --region us-east-1 --profile edisyl-registry)"Mint it at install time rather than saving it. The token lasts 12 hours, so one written into a file yesterday is already dead — and it is several kilobytes of base64, which is miserable to paste into YAML without mangling. Minting it inside the command keeps it off disk entirely and guarantees it is fresh.
Leave the flag off and the render stops with
images.pullSecretAuth.password must be set, so this is not something you can
forget silently.
The chart assembles the .dockerconfigjson itself from those three values —
computing the auth field as base64 of AWS:<token> — so you are never asked
to build that document by hand.
With ecrRefresh on, that seed is applied on install only, never on
upgrade — otherwise the two would fight, and every helm upgrade would paste a
token that died within twelve hours over whatever the refresher last wrote.
Three consequences worth knowing:
- Seeding an ECR credential this way with
ecrRefreshoff is refused at render. On its own it is a cluster that pulls today and cannot pull tomorrow. helm uninstallleaves this secret behind, because Helm does not track hook resources. Delete it by hand.- Under Argo CD, leave
pullSecretAuthoff and seed out of band: PreSync runs on every sync rather than once.
Or create it by hand. The profile you configured above already carries the role
and the external ID, so this needs no separate assume-role step:
kubectl -n edisyl create secret docker-registry edisyl-ecr \ --docker-server=944311261080.dkr.ecr.us-east-1.amazonaws.com \ --docker-username=AWS \ --docker-password="$(aws ecr get-login-password \ --region us-east-1 --profile edisyl-registry)" \ --dry-run=client -o yaml | kubectl apply -f -Three things about that command.
It is written to be re-run. kubectl create secret on its own fails with
AlreadyExists the second time, which is exactly when you need it — the token
lasts 12 hours, and a rebuild or an expired credential both send you back here.
Rendering the manifest and piping it to apply replaces the secret in place
instead.
The server is the registry HOST, with no path. images.registry carries
/edisyl-prd because it composes image references; a docker credential is
scoped to the host alone, and one written against the path-suffixed string is
simply never matched to the pull.
kubectl create secret docker-registry has no --docker-password-stdin, so
the token goes on the command line and your shell history will hold it. Clear it
afterwards if that matters to you.
Check what you actually created before installing — the secret is a
.dockerconfigjson document, and a wrong host or a truncated password is
invisible until a pod fails to pull:
kubectl -n edisyl get secret edisyl-ecr \ -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | python3 -m json.toolYou want one entry under auths, keyed by the registry host above, with
username: AWS and a non-empty password.
An imagePullSecret is namespace-local, so it has to live in the namespace
you install into — creating it in default and installing into edisyl leaves
the pull unauthenticated with nothing saying why.
Give the refresher an AWS identity
Section titled “Give the refresher an AWS identity”The pod’s own identity is what assumes the role above. It comes from IRSA —
name the role in ecrRefresh.serviceAccountAnnotations — or from EKS Pod
Identity, whose association is created outside Helm:
aws eks create-pod-identity-association \ --cluster-name "$CLUSTER" --namespace edisyl \ --service-account ecr-refresh --role-arn "$YOUR_ROLE_ARN" \ --disable-session-tags--disable-session-tags is not optional for a cross-account pull. Pod
Identity attaches transitive session tags by default, and a transitive tag
carried into the second AssumeRole requires the destination trust policy to
allow sts:TagSession. Our client role allows sts:AssumeRole only, so
leaving tags on fails the second hop with an AccessDenied that names neither
tags nor the reason.
A kubelet credential provider
Section titled “A kubelet credential provider”Cleanest where your distribution supports it. Configure
ecr-credential-provider on each node with the profile above. There is no
secret to rotate and nothing to refresh — leave both images.pullSecret and
ecrRefresh unset.
Verify
Section titled “Verify”Requires Docker. If you have not got it, the helm pull above is already
evidence that the role and the chart repository work.
aws ecr get-login-password --region us-east-1 --profile edisyl-registry \ | docker login --username AWS --password-stdin \ 944311261080.dkr.ecr.us-east-1.amazonaws.com
docker pull 944311261080.dkr.ecr.us-east-1.amazonaws.com/edisyl-prd/mono-api:<tag>Then confirm the boundary holds. Pick any repository not on the list we
gave you — this must fail with AccessDenied:
docker pull 944311261080.dkr.ecr.us-east-1.amazonaws.com/edisyl-prd/<not-granted>:<tag>If it succeeds, tell us immediately — it means your role is not scoped correctly.
Revoking
Section titled “Revoking”Tell us and we delete the role. New assumes fail at once; a token already issued keeps working until it expires, up to 12 hours later.
Was this page helpful?
Thanks for the feedback.
