EKS Pod Identity Configuration
Install the EKS Pod Identity Agent, configure IAM trust for pods.eks.amazonaws.com, create Pod Identity associations, and deploy the JFrog Registry Operator with authType: podIdentity.
EKS Pod Identity is a simpler alternative to IRSA for the JFrog Registry Operator: no OIDC provider and no role-arn ServiceAccount annotation required. It uses the EKS Pod Identity Agent (a DaemonSet add-on) and an EKS API association to map a cluster, namespace, and ServiceAccount directly to an IAM role.
Set spec.authType: podIdentity (or auto) in the SecretRotator CR to use this mechanism.
-
Install the EKS Pod Identity Agent.
The Pod Identity Agent must run on every worker node that schedules pods using Pod Identity. AWS installs it as an EKS-managed add-on (DaemonSet). If you use only
authType: webIdentity(IRSA), skip this EKS Pod Identity Configuration.Prerequisites
The Pod Identity Agent must be ACTIVE on nodes before the operator pod starts. Workloads require the agent on the same node as the pod.
Use one of the following methods:
-
Install via the AWS Console
- Open Amazon EKS > Clusters > your cluster.
- Open the Add-ons tab and select Get More Add-ons.
- Choose Amazon EKS Pod Identity Agent and complete the wizard.
-
Install via the AWS CLI
Find a compatible add-on version for your Kubernetes version:
aws eks describe-addon-versions \ --addon-name eks-pod-identity-agent \ --kubernetes-version <YOUR_K8S_VERSION> \ --query 'addons[0].addonVersions[*].addonVersion' \ --output textInstall the add-on:
aws eks create-addon \ --cluster-name <YOUR_CLUSTER_NAME> \ --addon-name eks-pod-identity-agent \ --addon-version <VERSION_FROM_ABOVE>Wait until the add-on status is ACTIVE, then verify the agent DaemonSet is running:
kubectl get pods -n kube-system -l app.kubernetes.io/name=eks-pod-identity-agent -o wide
-
IAM Role Trust Policy
The IAM role must trust
pods.eks.amazonaws.com, so EKS can assume it for Pod Identity.Create
trust-pod-identity.json:{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowEksAuthToAssumeRoleForPodIdentity", "Effect": "Allow", "Principal": { "Service": "pods.eks.amazonaws.com" }, "Action": [ "sts:AssumeRole", "sts:TagSession" ] } ] }Create a new role using the trust policy:
aws iam create-role \ --role-name <YOUR_ROLE_NAME> \ --assume-role-policy-document file://trust-pod-identity.json \ --description "EKS Pod Identity role for JFrog Registry Operator"To update an existing role's trust policy instead:
aws iam update-assume-role-policy \ --role-name <YOUR_ROLE_NAME> \ --policy-document file://trust-pod-identity.jsonCopy the role ARN from the output (for example,
arn:aws:iam::<ACCOUNT_ID>:role/<YOUR_ROLE_NAME>). You will need the role ARN in step 3.Combining with IRSA
If you also need IRSA on the same role, add a second statement to
trust-pod-identity.jsonwith your cluster OIDC provider as the principal andsts:AssumeRoleWithWebIdentityas the action. See the AWS documentation for the OIDC statement format. -
Attach the Permissions Policy
The JFrog Registry Operator passwordless flow requires the following permissions on the role:
sts:GetCallerIdentity: used in the signed request that JFrog validates.iam:GetRole: used to readMaxSessionDurationfor token TTL alignment. Createpolicy.json(replace<ACCOUNT_ID>and<YOUR_ROLE_NAME>):
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:GetCallerIdentity", "Resource": "arn:aws:iam::<ACCOUNT_ID>:role/<YOUR_ROLE_NAME>" }, { "Effect": "Allow", "Action": "iam:GetRole", "Resource": "arn:aws:iam::<ACCOUNT_ID>:role/<YOUR_ROLE_NAME>" } ] }Attach it as an inline policy:
aws iam put-role-policy \ --role-name <YOUR_ROLE_NAME> \ --policy-name <YOUR_INLINE_POLICY_NAME> \ --policy-document file://policy.json -
Create the Pod Identity association.
A Pod Identity association maps
(cluster, namespace, Kubernetes ServiceAccount name)to an IAM role ARN. Create the association before the operator pod starts.ServiceAccount Must Match
The operator pod must use
serviceAccountName: ${SERVICE_ACCOUNT_NAME}in the target namespace. If the pod runs under thedefaultServiceAccount, create the association fordefaultor update the Helm chart to use the intended ServiceAccount.Export variables to match the operator pod's ServiceAccount name and namespace:
export NAMESPACE=<namespace where the operator is deployed> export SERVICE_ACCOUNT_NAME=<operator Kubernetes ServiceAccount name> export ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/<YOUR_ROLE_NAME> export CLUSTER_NAME=<your EKS cluster name> export CLUSTER_REGION=<your EKS region name>Create the association:
aws eks create-pod-identity-association \ --cluster-name "${CLUSTER_NAME}" \ --namespace "${NAMESPACE}" \ --service-account "${SERVICE_ACCOUNT_NAME}" \ --role-arn "${ROLE_ARN}" --region "${CLUSTER_REGION}"If
create-pod-identity-associationfails because the namespace and ServiceAccount combination is already mapped, useupdate-pod-identity-associationor delete the existing association and recreate it.Verify the association was created:
aws eks list-pod-identity-associations --cluster-name "${CLUSTER_NAME}"To delete an association later:
aws eks delete-pod-identity-association \ --cluster-name "${CLUSTER_NAME}" \ --association-id <ASSOCIATION_ID> -
Configure JFrog Platform.
Configure the JFrog Platform to register the IAM role for passwordless access. Follow the same steps as for IRSA:
-
Install and configure the JFrog Registry Operator.
-
Export the namespace and ServiceAccount name.
export NAMESPACE=<namespace where the operator is deployed> export SERVICE_ACCOUNT_NAME=<operator Kubernetes ServiceAccount name> -
Add the JFrog Helm Charts repository.
helm repo add jfrog https://charts.jfrog.ioIf you have already added the repository, update it:
helm repo update -
Install the Custom Resource Definition (CRD) for the operator based on the required scope.
Default Scope
The default scope is cluster-scoped.
kubectl apply -f https://raw.githubusercontent.com/jfrog/jfrog-registry-operator/refs/heads/v3.1.1/config/crd/bases/apps.jfrog.com_secretrotators_cluster_scope.yamlkubectl apply -f https://raw.githubusercontent.com/jfrog/jfrog-registry-operator/refs/heads/v3.1.1/config/crd/bases/apps.jfrog.com_secretrotators_namespaced_scope.yaml -
Install the JFrog Registry Operator via Helm.
Pod Identity vs IRSA
For Pod Identity, no
serviceAccount.annotations(role ARN annotation) is needed. The Pod Identity association handles the mapping. The operator's ServiceAccount name must match the association created in step 3.helm upgrade --install secretrotator jfrog/jfrog-registry-operator \ --set "serviceAccount.name=${SERVICE_ACCOUNT_NAME}" \ --namespace "${NAMESPACE}" \ --create-namespace -
Verify the operator pod is running.
kubectl get pods -n "${NAMESPACE}" kubectl logs <pod-name> -n "${NAMESPACE}" -
Update
secretrotator.yamlwith the JFrog Platform URL and target namespace. Setspec.authType: podIdentity, or useautoto let the operator detect Pod Identity from injected environment variables.apiVersion: apps.jfrog.com/v1alpha1 kind: SecretRotator metadata: labels: app.kubernetes.io/name: secretrotators.apps.jfrog.com app.kubernetes.io/instance: secretrotator app.kubernetes.io/created-by: artifactory-secrets-rotator name: secretrotator spec: authType: podIdentity # auto | webIdentity | podIdentity namespaceSelector: matchLabels: kubernetes.io/metadata.name: <NAMESPACE> generatedSecrets: - secretName: token-imagepull-secret secretType: docker scope: - secretName: token-generic-secret secretType: generic scope: artifactoryUrl: "<JFROG_PLATFORM_URL>" serviceAccount: name: "" namespace: "" refreshTime: 30m secretMetadata: annotations: annotationKey: annotationValue labels: labelName: labelValue # security:Checking the Active Auth Type
status.authTypeon the SecretRotator (after a successful reconcile) reflects the effective mechanism used (podIdentityorwebIdentity), including whenauthType: autois set. -
Apply the manifest and verify that secrets are created in the target namespace.
kubectl apply -f secretrotator.yaml -n "${NAMESPACE}" kubectl get secrets -n "${NAMESPACE}"
-
Pod Identity Credential Scope
Each pod has one serviceAccountName, and one Pod Identity association maps that ServiceAccount to one IAM role. A single pod therefore receives one set of Pod Identity credentials. You cannot inject two separate Pod Identity identities into the same pod.
If your use case requires two IAM roles to be active simultaneously, use one of the following approaches:
- Two pods: Assign each pod a different ServiceAccount with its own Pod Identity association.
- One broader role: Consolidate the required permissions into a single IAM role.
sts:AssumeRolechaining: Grant the Pod Identity role permission to assume a second role when the IAM trust allows it.
The same constraint applies to IRSA: one pod uses one annotated ServiceAccount and assumes one role through the standard injected credential flow.
Resolution Checklist
Use this checklist to verify your configuration before raising a support ticket.
Pod Identity path (authType: podIdentity or auto with Pod Identity env vars)
- Pod Identity Agent add-on is ACTIVE on the nodes that run the operator pod.
- IAM role trust policy includes
pods.eks.amazonaws.comas the principal. - IAM permissions policy includes
sts:GetCallerIdentityandiam:GetRoleon the role ARN. - Pod Identity association matches the operator pod's namespace and ServiceAccount name exactly.
- Egress to
169.254.170.23:80is allowed. Proxy environment variables do not intercept that traffic. - IAM role is registered in JFrog Platform per Configure JFrog Platform for Passwordless Access to EKS.
- SecretRotator CR has
authType: podIdentityorauthType: auto.
IRSA path (authType: webIdentity or auto without Pod Identity env vars)
- IAM OIDC provider exists for the cluster issuer.
- IAM role trust policy includes
sts:AssumeRoleWithWebIdentitywith the correctsubandaudconditions. - IAM permissions policy includes
sts:GetCallerIdentityandiam:GetRoleon the role ARN. - Kubernetes ServiceAccount has the annotation
eks.amazonaws.com/role-arn: <IAM role ARN>. - IAM role is registered in JFrog Platform per Configure JFrog Platform for Passwordless Access to EKS.
- SecretRotator CR has
authType: webIdentityorauthType: auto.
Troubleshoot
Verify the Agent Is Running on the Correct Node
Confirm the Pod Identity Agent pod runs on the same node as your operator pod:
kubectl get pods -n kube-system -l app.kubernetes.io/name=eks-pod-identity-agent -o wide
kubectl get pod <operator-pod-name> -n "${NAMESPACE}" -o wideBoth pods must share the same node name in the NODE column.
Network Policy Blocks Credential Requests
If you use NetworkPolicy, the Pod Identity Agent serves credentials at the link-local address 169.254.170.23. Allow egress TCP port 80 to that address for any namespace running operator pods.
IAM AccessDenied on iam:GetRole
iam:GetRoleIf operator logs show a 403 error on iam:GetRole, add the iam:GetRole permission to the role's inline policy as described in step 2.
IRSA (webIdentity) Failures
webIdentity) Failures- Missing or wrong
role-arnannotation on the ServiceAccount: The EKS webhook will not injectAWS_ROLE_ARNor the token path into the pod.webIdentitywill fail silently. Verify the annotationeks.amazonaws.com/role-arnis present and matches the IAM role ARN. - Trust policy
submismatch: If the IAM trust condition contains the wrong namespace or ServiceAccount name, STS returnsAccessDeniedonAssumeRoleWithWebIdentity. Compare thesubcondition in the trust policy against the namespace and ServiceAccount name the pod uses. - OIDC provider missing: If no IAM OIDC identity provider is configured for the cluster issuer, IRSA cannot function. Create the OIDC provider in IAM before using
webIdentity.
Related Topics
| Topic | Description |
|---|---|
| How EKS Pod Identity Works | AWS documentation on how EKS Pod Identity operates at the platform level |
| IAM Roles for Service Accounts | AWS documentation on IRSA and OIDC-based credential injection |
Updated about 6 hours ago
