4. IAM与权限模型设计
在EKS上运行容器工作负载时,权限模型与EC2时代的做法有本质区别。EC2实例通常绑定一个实例配置文件,实例上所有进程共享同一套权限;而Kubernetes集群中,一个节点上可能同时运行几十个来自不同团队的Pod,如果它们共享节点IAM角色,任何一个Pod被攻破都可能拿到节点上所有AWS权限。因此,EKS的权限设计必须把“节点权限”和“Pod权限”彻底分离,并围绕IRSA(IAM Roles for Service Accounts)建立以服务账户为边界的授权体系。
一、三层权限边界:节点、Pod与Kubernetes RBAC
面向容器工作负载的IAM模型可以拆成三层。第一层是节点IAM角色,它由EKS托管节点组或自管节点的启动配置绑定,负责kubelet向EKS控制面注册、节点拉取基础镜像、上报日志等基础设施动作。这一层权限应当尽量收窄,只保留AmazonEKSWorkerNodePolicy、AmazonEC2ContainerRegistryReadOnly和AmazonEKS_CNI_Policy等必要托管策略,绝不能把业务所需的S3、DynamoDB权限挂在节点角色上。
第二层是Pod级IAM角色,通过IRSA把Kubernetes ServiceAccount与IAM Role关联。Pod内的AWS SDK会从注入的Web Identity Token文件读取OIDC令牌,再调用STS的AssumeRoleWithWebIdentity换取临时凭证。这一层是业务权限的主要载体,每个微服务对应一个独立角色。
第三层是Kubernetes RBAC,它控制Pod能访问哪些Kubernetes API资源,与IAM是正交的两套体系。IRSA解决“Pod能调用哪些AWS API”,RBAC解决“Pod能读写哪些K8s对象”,两者不能互相替代。
二、IRSA的信任策略与权限策略
IRSA的核心是IAM Role的信任策略。它必须限定OIDC提供方、受众和主体,其中sub条件键是防止跨命名空间冒用的关键。以下是一个订单服务的角色信任策略示例,命名空间为prod,服务账户为order-svc-sa:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.cn-north-1.amazonaws.com.cn/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.cn-north-1.amazonaws.com.cn/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
"oidc.eks.cn-north-1.amazonaws.com.cn/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:prod:order-svc-sa"
}
}
}]
}
权限策略则遵循最小权限原则。以订单服务为例,它需要从ECR拉取镜像(由节点角色完成,Pod本身不需要)、写入CloudWatch Logs、读写一张DynamoDB订单表、向SQS发送事件。策略中应把资源ARN写全,并利用条件键进一步收窄:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "WriteLogs",
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:cn-north-1:111122223333:log-group:/aws/eks/prod/order-svc:*"
},
{
"Sid": "OrderTableRW",
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:Query"],
"Resource": [
"arn:aws:dynamodb:cn-north-1:111122223333:table/orders",
"arn:aws:dynamodb:cn-north-1:111122223333:table/orders/index/*"
],
"Condition": {
"ForAllValues:StringEquals": {"dynamodb:LeadingKeys": ["${aws:PrincipalTag/tenant}"]}
}
},
{
"Sid": "SendEvents",
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:cn-north-1:111122223333:order-events"
}
]
}
注意ECR拉取权限的归属:Pod运行时并不需要ecr:GetAuthorizationToken或ecr:BatchGetImage,这些动作由节点上的kubelet以节点角色执行。如果使用Fargate,则由Fargate执行角色承担。把ECR拉取权限错误地授予Pod角色,是常见的权限膨胀来源。
三、服务账户与Pod的绑定方式
创建IRSA的完整链路包含四步:为集群创建OIDC提供方、创建IAM角色并写入信任策略、创建带eks.amazonaws.com/role-arn注解的ServiceAccount、在Deployment中引用该ServiceAccount。以下命令展示关键操作:
# 1. 关联 OIDC 提供方
eksctl utils associate-iam-oidc-provider \
--cluster prod-eks --region cn-north-1 --approve
# 2. 创建 ServiceAccount 并自动生成信任策略
eksctl create iamserviceaccount \
--cluster prod-eks --region cn-north-1 \
--namespace prod --name order-svc-sa \
--attach-policy-arn arn:aws:iam::111122223333:policy/OrderSvcPolicy \
--approve --override-existing-serviceaccounts
# 3. 验证注解
kubectl get sa order-svc-sa -n prod -o jsonpath='{.metadata.annotations}'
在Deployment中通过serviceAccountName: order-svc-sa引用后,EKS的Pod Identity Webhook会自动注入两个关键内容:环境变量AWS_ROLE_ARN、AWS_WEB_IDENTITY_TOKEN_FILE,以及挂载到/var/run/secrets/eks.amazonaws.com/serviceaccount/token的令牌卷。SDK会优先使用这套凭证链,无需在代码中硬编码任何密钥。
aws sts get-caller-identity,返回的Arn应为arn:aws:sts::111122223333:assumed-role/order-svc-role/...。如果返回的是节点角色Arn,说明注解未生效或Webhook未注入。四、最小权限的落地检查清单
权限设计完成后,建议用以下清单做一次审计,避免常见疏漏:
| 检查项 | 合格标准 | 常见问题 |
|---|---|---|
| 节点角色权限 | 仅含EKS Worker、ECR ReadOnly、CNI三项 | 误挂S3全读写 |
| 信任策略sub条件 | 精确到namespace:sa | 使用通配符*导致跨命名空间冒用 |
| 资源ARN粒度 | 表、队列、日志组写全名 | 使用*覆盖整个账号 |
| ECR拉取归属 | 由节点/Fargate执行角色承担 | 错误授予Pod角色 |
| 凭证有效期 | 默认1小时,按需调整 | 设置12小时且无轮换 |
| 权限边界 | 对高风险角色设置Permissions Boundary | 无边界,角色可自我提权 |
对于多租户场景,还可以在权限策略中使用aws:PrincipalTag条件键,把租户标识写入角色的标签,再让DynamoDB的LeadingKeys条件与之匹配,从而在同一个IAM角色下实现数据行级隔离。这种“角色共享、数据隔离”的模式比“每租户一个角色”更易维护,但要求标签管理严格,否则会形成越权风险。
iam:PassRole配合宽泛资源来允许Pod自行切换角色,这会让被攻破的Pod横向获取其他服务权限。若确需角色链,应把iam:PassedToService限定为eks.amazonaws.com,并只允许传递明确列出的角色ARN。最后,权限模型不是一次性配置。建议把IAM角色、策略、ServiceAccount注解全部纳入IaC(如Terraform或eksctl配置文件),在CI中执行iam-policy-validation与access-analyzer检查,任何权限变更都经过代码评审。这样既能保证最小权限持续有效,也能在出现安全事件时快速定位是哪一个服务账户、哪一条策略产生了越权路径。