IAM Roles for Service Accounts configuration
IAM Role for Service Account on EKS Anywhere clusters with self-hosted signing keys
IAM Roles for Service Account (IRSA) enables applications running in clusters to authenticate with AWS services using IAM roles. The current solution for leveraging this in EKS Anywhere involves creating your own OIDC provider for the cluster, and hosting your cluster’s public service account signing key. The public keys along with the OIDC discovery document should be hosted somewhere that AWS STS can discover it.
The steps below are based on the guide for configuring IRSA for DIY Kubernetes, with modifications specific to EKS Anywhere’s cluster provisioning workflow. The main modification is the process of generating the keys.json document. As per the original guide, the user has to create the service account signing keys, and then use that to create the keys.json document prior to cluster creation. This order is reversed for EKS Anywhere clusters, so you will create the cluster first, and then retrieve the service account signing key generated by the cluster, and use it to create the keys.json document. The sections below show how to do this in detail.
Create an OIDC provider and make its discovery document publicly accessible
You must use a single OIDC provider per EKS Anywhere cluster, which is the best practice to prevent a token from one cluster being used with another cluster. These steps describe the process of using a S3 bucket to host the OIDC discovery.json and keys.json documents.
-
Create an S3 bucket to host the public signing keys and OIDC discovery document for your cluster . Make a note of the
$HOSTNAMEand$ISSUER_HOSTPATH. -
Create the OIDC discovery document as follows:
cat <<EOF > discovery.json { "issuer": "https://$ISSUER_HOSTPATH", "jwks_uri": "https://$ISSUER_HOSTPATH/keys.json", "authorization_endpoint": "urn:kubernetes:programmatic_authorization", "response_types_supported": [ "id_token" ], "subject_types_supported": [ "public" ], "id_token_signing_alg_values_supported": [ "RS256" ], "claims_supported": [ "sub", "iss" ] } EOF -
Upload the
discovery.jsonfile to the S3 bucket:aws s3 cp ./discovery.json s3://$S3_BUCKET/.well-known/openid-configuration -
Create an OIDC provider for your cluster. Set the Provider URL to
https://$ISSUER_HOSTPATHand Audience tosts.amazonaws.com. -
Make a note of the
Providerfield of OIDC provider after it is created.
Create (or upgrade) the EKS Anywhere cluster
When creating (or upgrading) the EKS Anywhere cluster, you need to configure the kube-apiserver’s service-account-issuer flag so it can issue and mount projected service account tokens in pods. For this, use the value obtained in the first section for $ISSUER_HOSTPATH as the service-account-issuer. Configure the kube-apiserver by setting this value through the EKS Anywhere cluster spec:
apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Cluster
metadata:
name: my-cluster-name
spec:
podIamConfig:
serviceAccountIssuer: https://$ISSUER_HOSTPATH
Set the remaining fields in cluster spec as required and create the cluster.
Generate keys.json and make it publicly accessible
-
The cluster provisioning workflow generates a pair of service account signing keys. Retrieve the public signing key from the cluster and create a
keys.jsondocument with the content.git clone https://github.com/aws/amazon-eks-pod-identity-webhook cd amazon-eks-pod-identity-webhook kubectl get secret ${CLUSTER_NAME}-sa -n eksa-system -o jsonpath={.data.tls\\.crt} | base64 --decode > ${CLUSTER_NAME}-sa.pub go run ./hack/self-hosted/main.go -key ${CLUSTER_NAME}-sa.pub | jq '.keys += [.keys[0]] | .keys[1].kid = ""' > keys.json -
Upload the
keys.jsondocument to the S3 bucket.aws s3 cp ./keys.json s3://$S3_BUCKET/keys.json -
Use a bucket policy to grant public read access to the
discovery.jsonandkeys.jsondocuments:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::$S3_BUCKET/.well-known/openid-configuration",
"arn:aws:s3:::$S3_BUCKET/keys.json"
]
}
]
}
Deploy pod identity webhook
The Amazon Pod Identity Webhook
configures pods with the necessary environment variables and tokens (via file mounts) to interact with AWS services. The webhook will configure any pod associated with a service account that has an eks-amazonaws.com/role-arn annotation.
-
Clone amazon-eks-pod-identity-webhook .
-
Set the $KUBECONFIG environment variable to the path of the EKS Anywhere cluster.
-
Apply the manifests for the
amazon-eks-pod-identity-webhook. The image used here will be pulled from docker.io. Optionally, the image can be imported into (or proxied through) your private registry. Change theIMAGEargument here to your private registry if needed.make cluster-up IMAGE=amazon/amazon-eks-pod-identity-webhook:latest
Create IAM role for your workload
Each workload (such as ADOT, fluentbit, cert-manager, or custom applications) needs an IAM role with the permissions it requires. Repeat this section for each workload that requires AWS access.
-
Navigate to the AWS IAM Console.
-
Click on the OIDC provider created earlier.
-
Click Assign role.
-
Select Create a new role.
-
Select Web identity as the trusted entity.
-
In the Web identity section:
- If your Identity provider is not auto selected, select it.
- Select
sts.amazonaws.com.rproxy.govskope.caas the Audience.
-
Click Next.
-
Configure your desired Permissions poilicies.
-
Below is a sample trust policy of IAM role for your pods. Replace
ACCOUNT_ID,ISSUER_HOSTPATH,NAMESPACEandSERVICE_ACCOUNT. Example: Scoped to a service account{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/ISSUER_HOSTPATH" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "ISSUER_HOSTPATH:sub": "system:serviceaccount:NAMESPACE:SERVICE_ACCOUNT" }, } } ] } -
Create the IAM Role and make a note of the Role ARN.
-
Annotate your workload’s ServiceAccount with the IAM role ARN:
Example ServiceAccount:
apiVersion: v1 kind: ServiceAccount metadata: name: my-serviceaccount namespace: default annotations: eks.amazonaws.com/role-arn: "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" # optional: Defaults to "sts.amazonaws.com" if not set eks.amazonaws.com/audience: "sts.amazonaws.com" # optional: When set to "true", adds AWS_STS_REGIONAL_ENDPOINTS env var # to containers eks.amazonaws.com/sts-regional-endpoints: "true" # optional: Defaults to 86400 for expirationSeconds if not set # Note: This value can be overwritten if specified in the pod # annotation as shown in the next step. eks.amazonaws.com/token-expiration: "86400" -
See the How to use trust policies with IAM Roles for more information on trust policies.
Advanced: Sharing an IAM role across multiple clusters
When multiple EKS Anywhere clusters need access to the same AWS resources (e.g., multiple ADOT deployments writing to a shared AMP workspace), you can configure a single IAM role with multiple statements—one per cluster’s OIDC provider.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/s3.us-west-2.amazonaws.com/dev-bucket"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"s3.us-west-2.amazonaws.com/dev-bucket:aud": "sts.amazonaws.com",
"s3.us-west-2.amazonaws.com/dev-bucket:sub": "system:serviceaccount:observability:adot-collector"
}
}
},
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/s3.us-west-2.amazonaws.com/staging-bucket"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"s3.us-west-2.amazonaws.com/staging-bucket:aud": "sts.amazonaws.com",
"s3.us-west-2.amazonaws.com/staging-bucket:sub": "system:serviceaccount:observability:adot-collector"
}
}
},
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/s3.us-west-2.amazonaws.com/prod-bucket"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"s3.us-west-2.amazonaws.com/prod-bucket:aud": "sts.amazonaws.com",
"s3.us-west-2.amazonaws.com/prod-bucket:sub": "system:serviceaccount:observability:adot-collector"
}
}
}
]
}