IAM Roles and Policies
AosCloud uses IAM roles at multiple levels — EKS Pod Identity or IRSA (IAM Roles for Service Accounts) for Kubernetes pods, EKS system roles for cluster components, and admin roles for infrastructure management. This page documents every role, its trust policy, and the precise permissions it requires.
Prerequisites
Before configuring IAM roles:
- Review Required AWS Services to understand which AWS services the roles need to access
- Confirm your AWS account has permission to create IAM roles, policies, and OIDC identity providers
- Identify any organizational permission boundaries (SCPs, permission boundaries) that may constrain role creation
Pod-to-AWS Authentication
AosCloud supports two mechanisms for granting Kubernetes pods access to AWS services:
EKS Pod Identity (Recommended)
The modern approach. EKS Pod Identity simplifies IAM role association without requiring an OIDC identity provider. It uses the EKS Pod Identity Agent (a DaemonSet) to issue credentials to pods.
Key benefits over IRSA:
- No OIDC provider management — configured directly through the EKS API
- Single
pods.eks.amazonaws.comtrust principal for all clusters - Credentials assumed once per node (more scalable)
- Cleaner separation of duties between cluster and IAM administration
Trust policy pattern:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
Setup: Install the EKS Pod Identity Agent addon, then create Pod Identity associations via the EKS API linking service accounts to IAM roles.
IRSA — IAM Roles for Service Accounts (Legacy)
The legacy approach. IRSA relies on an OpenID Connect (OIDC) identity provider that links Kubernetes service accounts to IAM roles via web identity federation.
Service Accounts (Application Workloads)
These roles are assumed by Kubernetes pods running AosCloud microservices. Each is bound to a specific service account name and grants only the AWS permissions that workload requires.
IRSA Trust Policy Pattern
When using IRSA, all application roles use a common trust policy pattern:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal": {
"Federated": "<OIDC-provider-ARN>"
},
"Condition": {
"StringLike": {
"<OIDC-issuer-URL>:sub": "system:serviceaccount:*:<service-account-name>"
}
}
}
]
}
The StringLike condition with wildcard namespace (*) allows the service account to function across namespaces during development. For production hardening, replace with StringEquals and a specific namespace.
Service Account Inventory
| Service Account | Naming Pattern | Used By | Namespace |
|---|---|---|---|
sa_app | {project}-{env}-app | API, Auth, and Frontend pods | {environment} |
sa_task | {project}-{env}-task | Backend task workers, Message Handler | {environment} |
sa_sd | {project}-{env}-sd | Service Discovery pods | {environment} |
sa_secrets_manager | {project}-{env}-secrets-manager | Secrets CSI driver pods | {environment} |
sa_base | {project}-{env}-base | Core platform pods (broad access) | {environment} |
sa_data_services | {project}-{env}-data-services | Data service pods | {environment} |
sa_uqm | {project}-{env}-qm | Unit monitoring pods | {environment} |
Permissions by Service Account
sa_app — Application Pods
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
default_backend | S3: GetObject, PutObject, DeleteObject, ListBucket; KMS: Encrypt, Decrypt, GenerateDataKey | Backend S3 bucket, KMS key | Read/write Deployable Items and application data |
sa_task — Task Workers and Message Handler
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
ec2_task | EC2: RunInstances, DescribeInstances, DescribeLaunchTemplates, CreateTags, TerminateInstances | EC2 instances with tag managedby=aos-app | Manage EC2 instances for Unit image building |
default_backend | S3 + KMS read/write | Backend S3 bucket | Access Deployable Items |
secrets_manager_rw | Secrets Manager: full CRUD; KMS: Encrypt, Decrypt | Secrets at path {project}-{env}* | Manage application secrets |
sa_sd — Service Discovery
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
default_backend | S3 + KMS read/write | Backend S3 bucket | Access service configuration data |
sa_secrets_manager — Secrets CSI Provider
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
secrets_manager_rw | Secrets Manager: GetSecretValue, CreateSecret, UpdateSecret, DeleteSecret, ListSecrets; KMS: Encrypt, Decrypt, GenerateDataKey | Secrets at path {project}-{env}*, KMS key | Mount secrets as volumes in pods via CSI driver |
sa_base — Core Platform (Broadest Privileges)
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
default_backend | S3 + KMS read/write | Backend S3 bucket | Application data |
secrets_manager_rw | Secrets Manager + KMS full access | Secrets at path {project}-{env}* | Secret management |
ec2_task | EC2 instance lifecycle | Tagged EC2 instances | Image building |
s3_infra | S3 + KMS read/write | Infrastructure S3 bucket | Infrastructure artifacts |
saas | aws-marketplace:ResolveCustomer, BatchMeterUsage, GetEntitlements; sts:AssumeRole; sqs:* | Marketplace resources, SaaS role ARN | AWS Marketplace SaaS integration |
CloudWatchAgentServerPolicy | CloudWatch Logs and Metrics publishing | All resources | Metrics and log forwarding |
sa_data_services — Data Services
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
default_backend | S3 + KMS read/write | Backend S3 bucket | Data persistence |
sa_uqm — Unit Monitoring
| Policy | AWS Actions | Resources | Purpose |
|---|---|---|---|
default_backend | S3 + KMS read/write | Backend S3 bucket | Monitoring data storage |
ec2_task | EC2 instance operations | Tagged EC2 instances | Fleet monitoring operations |
Service Accounts (EKS System Components)
These roles serve Kubernetes system components. They operate in the kube-system namespace.
System Service Account Inventory
| Service Account | Role Name Pattern | Kubernetes Identity | Policies |
|---|---|---|---|
| Cluster Autoscaler | {cluster}-autoscaling-role | kube-system:aws-node, kube-system:cluster-autoscaler | Custom autoscaler policy |
| AWS Load Balancer Controller | {cluster}-load-balancer-controller | kube-system:aws-load-balancer-controller | Custom LB controller policy |
| EBS CSI Driver | {cluster}-ebs-controller | kube-system:ebs-csi-* | AmazonEBSCSIDriverPolicy (AWS-managed) |
| EFS CSI Driver | {cluster}-efs-controller | kube-system:efs-csi* | AmazonEFSCSIDriverPolicy (AWS-managed) |
| VPC CNI | {cluster}-vpc-cni-controller | kube-system:aws-node* | AmazonEKS_CNI_Policy (AWS-managed) |
Cluster Autoscaler Permissions
{
"Statement": [
{
"Sid": "clusterAutoscalerAll",
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeTags",
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
"ec2:DescribeLaunchTemplateVersions",
"ec2:DescribeInstanceTypes",
"ec2:DescribeImages",
"ec2:GetInstanceTypesFromInstanceRequirements",
"eks:DescribeNodegroup"
],
"Resource": "*"
},
{
"Sid": "clusterAutoscalerOwn",
"Effect": "Allow",
"Action": [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
"autoscaling:UpdateAutoScalingGroup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/k8s.io/cluster-autoscaler/${CLUSTER_ID}": "owned",
"autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled": "true"
}
}
}
]
}
The second statement restricts mutating operations to Auto Scaling groups owned by this specific cluster.
AWS Load Balancer Controller Permissions
The LB controller requires broad read access to EC2/ELB resources plus write access to manage load balancers and target groups. Key actions include:
ec2:Describe*— discover VPCs, subnets, security groupselasticloadbalancing:*— full ALB/NLB lifecycle managementiam:CreateServiceLinkedRole— for ELB service-linked role (conditioned onelasticloadbalancing.amazonaws.com)cognito-idp:DescribeUserPoolClient— for Cognito-authenticated ALBswafv2:*,shield:*— WAF and Shield association with ALBsacm:DescribeCertificate,acm:ListCertificates— TLS certificate discovery
The LB controller policy is comprehensive — see the AWS Load Balancer Controller documentation for the full IAM policy reference.
EKS Cluster Roles
Control Plane Role
| Property | Value |
|---|---|
| Name pattern | {cluster}-role |
| Trust principal | eks.amazonaws.com |
| Managed policies | AmazonEKSClusterPolicy, AmazonEKSServicePolicy, AmazonEKSVPCResourceController |
| Purpose | Allows the EKS control plane to manage AWS resources on behalf of the cluster |
Node Group Role
| Property | Value |
|---|---|
| Name pattern | {cluster}-node-role |
| Trust principal | ec2.amazonaws.com |
| Managed policies | AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, CloudWatchAgentServerPolicy, AmazonEC2ContainerRegistryReadOnly, AmazonEC2ContainerRegistryPowerUser |
| Purpose | Grants worker nodes permissions to join the cluster, pull container images, and publish logs |
Permission Boundaries
All roles created by the infrastructure support an optional permission boundary. When set, every role (service accounts, EKS) cannot exceed the permissions defined in the boundary policy, regardless of what policies are attached.
This is useful for organizations with central security teams that enforce guardrails on delegated IAM role creation.
IAM Policy Templates Reference
The infrastructure uses parameterized JSON policy templates. Below is a summary of each custom policy:
| Policy Template | Parameters | Scope |
|---|---|---|
policy-rw-s3.json | BUCKET, KMS_KEY_ARN | S3 read/write + KMS encrypt/decrypt on a specific bucket |
policy-secrets-manager.json | SECRET_PATH_ARN, KMS_ARN | Full Secrets Manager CRUD scoped to a path prefix + KMS operations |
policy-ec2-task.json | REGION, ACCOUNTNUMBER, TAG_KEY, TAG_VALUE, LAUNCH_TEMPLATE | EC2 instance lifecycle constrained by tags and launch templates |
policy-saas.json | AWS_SAAS_ARN | AWS Marketplace metering + cross-account STS assume |
Role Architecture Diagram
Security Recommendations
- Use EKS Pod Identity where possible — It's simpler to manage and more scalable than IRSA. IRSA remains supported for system components that don't yet support Pod Identity.
- Tighten trust conditions — When using IRSA, replace
StringLikewithStringEqualsand specify exact namespace in production to prevent cross-namespace impersonation - Enable permission boundaries — Set a permission boundary ARN to enforce organizational guardrails
- Audit with CloudTrail — All
AssumeRoleWithWebIdentityandAssumeRolecalls are logged, enabling pod-level attribution of AWS API calls - Scope
sa_basedown — The base service account has the broadest permissions; consider splitting into more granular roles if your security posture requires it
Related Documentation
- Required AWS Services — services these roles grant access to
- Infrastructure — overview and reading order
- Kubernetes Deployment Architecture — how service accounts bind to pods