Granular IAM Roles
ACK supports using multiple IAM roles with fine-grained control over which role is used for different resources or namespaces. This enables scenarios like managing resources across multiple AWS accounts or using different permission sets within the same account.
Choose Your Method​
- IAM Role Selector (Recommended)
- CARM
The IAM Role Selector uses a cluster-scoped CRD to dynamically map IAM roles to namespaces and resources using Kubernetes label selectors. This is the recommended method for multi-role and cross-account resource management.
Overview​
IAM Role Selector introduces the IAMRoleSelector CRD, which allows cluster administrators to:
- Define IAM roles that ACK controllers can assume
- Use namespace selectors (names or label selectors) to control where roles can be used
- Optionally scope roles to specific API versions or resource kinds
- Dynamically configure role usage without requiring resource-level annotations
Prerequisites​
- Source Account: The AWS account where your ACK controller runs
- Target Account: The AWS account where you want to create/manage resources
- Cross-account IAM role: A role in the target account that trusts the source account
- Feature enabled: IAM Role Selector must be enabled via feature flag when installing ACK
Step 1: Create Cross-Account IAM Role​
In the target account, create an IAM role that trusts the source account's controller role
# In the target account
export SOURCE_ACCOUNT_ROLE_ARN="arn:aws:iam::111111111111:role/ack-controller-role"
# Create trust policy
cat > trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "${SOURCE_ACCOUNT_ROLE_ARN}"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# Create the role
aws iam create-role \
--role-name ACK-CrossAccount-Target \
--assume-role-policy-document file://trust-policy.json
# Attach necessary permissions (example for S3)
aws iam attach-role-policy \
--role-name ACK-CrossAccount-Target \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
Step 2: Grant AssumeRole Permission to Controller​
In the source account, ensure your ACK controller's IAM role can assume the target role
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/ACK-CrossAccount-Target"
}
]
}
Step 3: Create IAMRoleSelector Resource​
Create an IAMRoleSelector to map the IAM role to specific namespaces or resources:
Example 1: Map role to specific namespace
apiVersion: services.k8s.aws/v1alpha1
kind: IAMRoleSelector
metadata:
name: production-account-config
spec:
arn: arn:aws:iam::222222222222:role/ACK-CrossAccount-Target
namespaceSelector:
names:
- production
Example 2: Map role using namespace labels
apiVersion: services.k8s.aws/v1alpha1
kind: IAMRoleSelector
metadata:
name: dev-team-config
spec:
arn: arn:aws:iam::222222222222:role/ACK-CrossAccount-Target
namespaceSelector:
names: [] # Empty names array required, matches no specific names
labelSelector:
matchLabels:
environment: development
team: sky-team
Example 3: Map role to specific resource types
apiVersion: services.k8s.aws/v1alpha1
kind: IAMRoleSelector
metadata:
name: s3-buckets-only
spec:
arn: arn:aws:iam::222222222222:role/ACK-CrossAccount-S3
namespaceSelector:
names:
- production
resourceTypeSelector:
- group: s3.services.k8s.aws
version: v1alpha1
kind: Bucket # Only S3 Buckets, not other S3 resources
Example 4: Cluster-wide role for all resources
apiVersion: services.k8s.aws/v1alpha1
kind: IAMRoleSelector
metadata:
name: cluster-wide-config
spec:
arn: arn:aws:iam::222222222222:role/ACK-CrossAccount-Target
# No selectors = matches all namespaces and resources
Step 4: Create Resources​
Once the IAMRoleSelector is configured, simply create resources in the matching namespace:
apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
name: cross-account-bucket
namespace: production # Matches IAMRoleSelector
spec:
name: my-bucket-in-target-account
ACK will automatically use the matched IAM role when managing this resource. The resource status will show which selector was used via a condition:
status:
ackResourceMetadata:
arn: arn:aws:s3:::my-bucket-in-target-account
conditions:
- type: ACK.IAMRoleSelected
status: "True"
message: "roleARN: arn:aws:iam::222222222222:role/ACK-CrossAccount-Target, selectorName: production-account-config, selectorResourceVersion: 89424719"
Selection Logic​
- Multiple selectors can be defined; ACK evaluates all of them for each resource
- If exactly one
IAMRoleSelectormatches, that role is used - If no
IAMRoleSelectormatches, the default controller role is used - If multiple
IAMRoleSelectors match, a conflict occurs and the resource shows an error condition
Conflict Example:
status:
conditions:
- message: |-
Cannot determine which IAMRoleSelector to use.
Conflicting IAMRoleSelectors: [production-account-config, s3-buckets-only]
status: "True"
type: ACK.Recoverable
To resolve conflicts, update or delete one of the conflicting selectors, or make them more specific.
Enabling the Feature​
IAM Role Selector must be enabled via feature flag when installing ACK:
helm install -n ack-system ack-s3-controller \
oci://public.ecr.aws/aws-controllers-k8s/s3-chart \
--set featureGates.IAMRoleSelector=true
Enabling IAM Role Selector disables CARM. These features cannot be used together.
CARM (Cross-Account Resource Management) is being deprecated.
For new implementations, use the IAM Role Selector approach instead. Existing CARM configurations will continue to work but migration to IAM Role Selector is recommended.
What is CARM?​
CARM is ACK's original cross-account resource management feature that uses ConfigMaps to define account mappings.
How CARM Works​
CARM maps namespaces to AWS accounts and IAM roles using a ConfigMap:
Basic Setup:
- Create a ConfigMap defining account mappings:
apiVersion: v1
kind: ConfigMap
metadata:
name: ack-role-account-map
namespace: ack-system
data:
"222222222222": arn:aws:iam::222222222222:role/ACK-CrossAccount-Prod
"333333333333": arn:aws:iam::333333333333:role/ACK-CrossAccount-Staging
- Annotate namespaces with the account ID:
kubectl annotate namespace production \
services.k8s.aws/owner-account-id=222222222222
kubectl annotate namespace staging \
services.k8s.aws/owner-account-id=333333333333
- Create resources in the annotated namespace:
apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
name: prod-bucket
namespace: production
spec:
name: my-production-bucket
The controller automatically uses the role mapped to 222222222222 for resources in the production namespace.
Team-Level CARM (Advanced)​
For multiple roles within the same account, CARM supports a team-level mapping:
apiVersion: v1
kind: ConfigMap
metadata:
name: ack-role-account-map
namespace: ack-system
data:
"222222222222": arn:aws:iam::222222222222:role/ACK-Default
"team-a": arn:aws:iam::222222222222:role/ACK-TeamA
"team-b": arn:aws:iam::222222222222:role/ACK-TeamB
Then annotate namespaces with team IDs:
kubectl annotate namespace team-a-ns \
services.k8s.aws/owner-account-id=team-a
Limitations​
- Uses untyped ConfigMaps (no schema validation)
- Requires namespace annotations (implicit permission model)
- Cannot differentiate roles by resource type within a namespace
- Account ID strings don't have to match actual account IDs (confusing semantics)
- Difficult to iterate without breaking existing configurations
Migration to IAM Role Selector​
To migrate from CARM to IAM Role Selector:
- Note your existing role ARNs from the ConfigMap
- Create equivalent
IAMRoleSelectorresources:
# Before (CARM ConfigMap entry)
# data:
# "222222222222": arn:aws:iam::222222222222:role/ACK-CrossAccount-Prod
# After (IAMRoleSelector)
apiVersion: services.k8s.aws/v1alpha1
kind: IAMRoleSelector
metadata:
name: production-config
spec:
arn: arn:aws:iam::222222222222:role/ACK-CrossAccount-Prod
namespaceSelector:
names:
- production
- Remove namespace annotations
- Delete the CARM ConfigMap
- Enable IAM Role Selector feature flag
Troubleshooting​
Access Denied Errors​
If you see access denied errors:
- Verify trust policy: Ensure the target role trusts the source account's controller role
- Check permissions: Confirm the target role has necessary service permissions
- AssumeRole permission: Verify the source controller role can call
sts:AssumeRole - Role ARN format: Double-check the role ARN syntax
IAMRoleSelector Not Matching​
If resources aren't using the expected role:
- Check selectors: Verify namespace names or labels match the selector
- Check conflicts: Look for multiple matching selectors in resource status
- Feature enabled: Confirm
IAMRoleSelectorfeature flag is set - Namespace labels: Ensure label selectors match actual namespace labels
Check Controller Logs​
kubectl logs -n ack-system deployment/ack-<service>-controller | grep -i "assume"
Look for messages about role assumption failures or selector conflicts.
Best Practices​
- Least privilege: Grant only necessary permissions to cross-account roles
- External ID: Consider using external IDs for additional security
- Clear naming: Use descriptive names for IAMRoleSelector resources
- Namespace labels: Use consistent labeling for dynamic namespace selection
- Monitoring: Set up CloudTrail to monitor cross-account access
- Avoid conflicts: Design selectors to avoid overlapping resource matches
Next Steps​
- Configure deletion policies for cross-account resources
- Set up cross-region deployments
- Adopt existing resources in target accounts