Configure IAM Permissions for ACK Controllers
ACK controllers need AWS IAM permissions to manage resources. This guide shows you how to configure IAM permissions using either EKS Pod Identity (recommended for EKS 1.24+) or IRSA (traditional method).
Click to zoom • Pod Identity authentication flow
Choose Your Authentication Method​
- Pod Identity (Recommended)
- IRSA
What is Pod Identity?​
EKS Pod Identity is a feature that allows pods running in your EKS cluster to assume AWS IAM roles without requiring OIDC configuration. It simplifies the authentication flow by using the EKS Pod Identity Agent, which runs as a DaemonSet in your cluster and handles credential requests automatically.
How It Works​
-
You create a Pod Identity Association that links:
- An IAM role (with AWS service permissions)
- A Kubernetes service account (used by the ACK controller)
- A namespace (where the controller runs)
-
When the ACK controller pod starts with this service account, the Pod Identity Agent automatically provides temporary AWS credentials
-
The controller uses these credentials to manage AWS resources
Pod Identity Association​
A Pod Identity Association is an EKS resource that connects your controller's service account to an IAM role. Here's what it looks like:
apiVersion: eks.services.k8s.aws/v1alpha1
kind: PodIdentityAssociation
metadata:
name: ack-s3-controller-pod-identity
spec:
clusterName: my-cluster
namespace: ack-system
serviceAccount: ack-s3-controller
roleARN: arn:aws:iam::123456789012:role/ack-s3-controller
Key components:
clusterName: Your EKS cluster namenamespace: Where your ACK controller runs (typicallyack-system)serviceAccount: The service account used by the controller (auto-created during installation)roleARN: The IAM role with permissions for the AWS service
You can create this using either:
- AWS CLI:
aws eks create-pod-identity-association - ACK EKS Controller: Create a
PodIdentityAssociationCRD (shown above)
Example Configuration​
Here's a complete example for configuring the S3 controller with Pod Identity:
# Variables
export SERVICE=s3
export CLUSTER_NAME=my-cluster
export AWS_REGION=us-west-2
export ACK_SYSTEM_NAMESPACE=ack-system
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# Create Pod Identity Association
aws eks create-pod-identity-association \
--cluster-name $CLUSTER_NAME \
--namespace $ACK_SYSTEM_NAMESPACE \
--service-account ack-${SERVICE}-controller \
--role-arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/ack-${SERVICE}-controller \
--region $AWS_REGION
# Restart controller to pick up the association
kubectl rollout restart deployment -n $ACK_SYSTEM_NAMESPACE \
ack-${SERVICE}-controller
Or using the ACK EKS controller:
apiVersion: eks.services.k8s.aws/v1alpha1
kind: PodIdentityAssociation
metadata:
name: ack-s3-controller-pod-identity
spec:
clusterName: my-cluster
namespace: ack-system
serviceAccount: ack-s3-controller
roleARN: arn:aws:iam::123456789012:role/ack-s3-controller
Creating the IAM Role (expand for details)
Before creating the Pod Identity Association, you need an IAM role with the appropriate permissions.
Step 1: Create IAM Role with Pod Identity Trust Policy
export SERVICE=s3
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# Create IAM role with Pod Identity trust policy
aws iam create-role \
--role-name ack-${SERVICE}-controller \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "pods.eks.amazonaws.com"},
"Action": ["sts:AssumeRole", "sts:TagSession"]
}]
}'
Step 2: Attach AWS Service Permissions
# Get recommended policy for your service
export POLICY_ARN=$(curl -s https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-policy-arn)
# Attach the policy
aws iam attach-role-policy \
--role-name ack-${SERVICE}-controller \
--policy-arn $POLICY_ARN
Step 3: Attach Inline Policies (if needed)
Some controllers need additional inline policies (like iam:PassRole):
# Check if inline policy exists
curl -s https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-inline-policy > inline-policy.json
# If the file exists and has content, apply it
if [ -s inline-policy.json ]; then
aws iam put-role-policy \
--role-name ack-${SERVICE}-controller \
--policy-name ack-${SERVICE}-inline \
--policy-document file://inline-policy.json
fi
Verify​
Check that the Pod Identity Association was created:
aws eks list-pod-identity-associations \
--cluster-name $CLUSTER_NAME \
--region $AWS_REGION
# Check controller logs
kubectl logs -n $ACK_SYSTEM_NAMESPACE deployment/ack-${SERVICE}-controller
What is IRSA?​
IAM Roles for Service Accounts (IRSA) uses OpenID Connect (OIDC) to allow Kubernetes service accounts to assume AWS IAM roles. It's the traditional method for providing AWS permissions to pods in EKS.
How It Works​
- Your EKS cluster has an OIDC provider that acts as an identity provider
- You create an IAM role with a trust policy that trusts your cluster's OIDC provider
- You annotate the Kubernetes service account with the IAM role ARN
- When pods use this service account, they can assume the IAM role and get temporary AWS credentials
Service Account Annotation​
With IRSA, you link an IAM role to a service account using an annotation:
apiVersion: v1
kind: ServiceAccount
metadata:
name: ack-s3-controller
namespace: ack-system
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/ack-s3-controller
This annotation tells EKS to provide credentials for the specified IAM role when pods use this service account.
Example Configuration​
Here's a complete example for configuring the S3 controller with IRSA:
# Variables
export SERVICE=s3
export CLUSTER_NAME=my-cluster
export AWS_REGION=us-west-2
export ACK_SYSTEM_NAMESPACE=ack-system
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# Get OIDC provider URL
export OIDC_PROVIDER=$(aws eks describe-cluster --name $CLUSTER_NAME \
--region $AWS_REGION \
--query "cluster.identity.oidc.issuer" \
--output text | sed -e "s/^https:\/\///")
# Annotate service account
kubectl annotate serviceaccount -n $ACK_SYSTEM_NAMESPACE \
ack-${SERVICE}-controller \
eks.amazonaws.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/ack-${SERVICE}-controller
# Restart controller to pick up the annotation
kubectl rollout restart deployment -n $ACK_SYSTEM_NAMESPACE \
ack-${SERVICE}-controller
Setting up OIDC and IAM Role (expand for details)
Before using IRSA, you need to set up the OIDC provider and create an IAM role.
Step 1: Enable OIDC Provider (if not already enabled)
export CLUSTER_NAME=my-cluster
export AWS_REGION=us-west-2
# Check if OIDC provider exists
aws eks describe-cluster --name $CLUSTER_NAME --region $AWS_REGION \
--query "cluster.identity.oidc.issuer" --output text
# If not configured, create it with eksctl
eksctl utils associate-iam-oidc-provider \
--cluster=$CLUSTER_NAME \
--region=$AWS_REGION \
--approve
Step 2: Create IAM Role with OIDC Trust Policy
export SERVICE=s3
export ACK_SYSTEM_NAMESPACE=ack-system
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
export OIDC_PROVIDER=$(aws eks describe-cluster --name $CLUSTER_NAME \
--region $AWS_REGION \
--query "cluster.identity.oidc.issuer" \
--output text | sed -e "s/^https:\/\///")
# Create trust policy
cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${ACK_SYSTEM_NAMESPACE}:ack-${SERVICE}-controller",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}]
}
EOF
# Create the role
aws iam create-role \
--role-name ack-${SERVICE}-controller \
--assume-role-policy-document file://trust-policy.json
Step 3: Attach AWS Service Permissions
# Get recommended policy
export POLICY_ARN=$(curl -s https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-policy-arn)
# Attach the policy
aws iam attach-role-policy \
--role-name ack-${SERVICE}-controller \
--policy-arn $POLICY_ARN
Step 4: Attach Inline Policies (if needed)
# Check if inline policy exists
curl -s https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-inline-policy > inline-policy.json
# If the file exists and has content, apply it
if [ -s inline-policy.json ]; then
aws iam put-role-policy \
--role-name ack-${SERVICE}-controller \
--policy-name ack-${SERVICE}-inline \
--policy-document file://inline-policy.json
fi
Verify​
Check that the service account has the annotation:
# Check service account annotation
kubectl get sa -n $ACK_SYSTEM_NAMESPACE ack-${SERVICE}-controller -o yaml
# Check controller logs
kubectl logs -n $ACK_SYSTEM_NAMESPACE deployment/ack-${SERVICE}-controller
Finding Recommended Policies​
Each ACK controller repository contains recommended IAM policies:
# Policy ARN (AWS managed policy)
https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-policy-arn
# Inline policy (additional permissions)
https://raw.githubusercontent.com/aws-controllers-k8s/${SERVICE}-controller/main/config/iam/recommended-inline-policy
Examples:
- S3:
arn:aws:iam::aws:policy/AmazonS3FullAccess - DynamoDB:
arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess - RDS:
arn:aws:iam::aws:policy/AmazonRDSFullAccess
For production, create custom policies with least-privilege permissions instead of using *FullAccess policies.