2. Karpenter 控制器权限与 IRSA 配置排查

Karpenter 控制器权限与 IRSA 配置排查 学习卡片

IRSA 权限链路:从 ServiceAccount 到 EC2 动作

Karpenter 控制器要能创建、终止 EC2 实例并读取价格、子网、安全组等信息,必须通过 IRSA(IAM Roles for Service Accounts)获得 AWS 权限。排查时不要只看 Pod 是否 Running,而要沿着“ServiceAccount → OIDC 信任 → IAM Role → 权限策略 → AWS API 调用”这条链路逐段确认。

Karpenter 控制器 IRSA 权限链路与排查点 ServiceAccount karpenter namespace: kube-system annotation: role-arn EKS OIDC Provider oidc.eks.<region> .amazonaws.com/id/XXXX 信任策略 sub 条件 IAM Role KarpenterControllerRole AssumeRoleWithWebIdentity 信任策略绑定 OIDC 权限策略 ec2:RunInstances ec2:TerminateInstances ec2:Describe* AWS API 调用验证(Karpenter 控制器实际发出的请求) ec2:RunInstances 创建节点实例 需 subnet/sg/ami 权限 ec2:TerminateInstances 缩容/回收节点 需实例状态读取权限 ec2:Describe* 子网/安全组/AMI/实例 资源发现与状态同步 pricing:GetProducts 实例价格查询 成本感知调度 AssumeRole 后调用 排查判断:日志与错误码对照 AccessDenied / UnauthorizedOperation → 权限策略缺少对应 Action → 检查 IAM Policy 是否绑定到 Role InvalidIdentityToken / STS 错误 → OIDC Provider 未创建或 ARN 不匹配 → 信任策略 sub 条件写错 无法读取子网/安全组 → DescribeSubnets 等只读权限缺失 → 检查 Resource 是否限制过窄 失败时对照

配置 IRSA 的关键步骤

以下操作假设集群已启用 OIDC Provider,且 Karpenter 安装在 kube-system 命名空间。先确认 OIDC Provider 是否存在:

aws eks describe-cluster --name <cluster-name> \
  --query "cluster.identity.oidc.issuer" --output text

输出形如 https://oidc.eks.cn-north-1.amazonaws.com.cn/id/EXAMPLED539D4633E53DE1B71EXAMPLE。若该 Provider 未在 IAM 中注册,需先创建:

eksctl utils associate-iam-oidc-provider \
  --cluster <cluster-name> --approve

接着创建信任策略文件 karpenter-trust-policy.json,将 <OIDC_ID> 替换为上一步输出中的 ID:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<OIDC_ID>"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.<region>.amazonaws.com/id/<OIDC_ID>:sub": "system:serviceaccount:kube-system:karpenter",
          "oidc.eks.<region>.amazonaws.com/id/<OIDC_ID>:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}

创建 IAM Role 并附加最小权限策略。Karpenter 控制器需要的核心权限包括:

权限类别Action 示例用途
实例生命周期ec2:RunInstances、ec2:TerminateInstances创建与终止节点
资源发现ec2:DescribeSubnets、ec2:DescribeSecurityGroups、ec2:DescribeImages选择子网、安全组、AMI
实例状态ec2:DescribeInstances、ec2:DescribeInstanceTypes同步节点状态与规格
价格查询pricing:GetProducts成本感知的实例选择
IAM 传递iam:PassRole为节点实例传递 NodeRole
最小权限原则:ec2:RunInstances 的 Resource 应限制为具体的 AMI、子网、安全组 ARN,而不是 *。但排查阶段可先放宽到 * 确认链路通,再逐步收紧。

验证控制器是否真正具备权限

配置完成后,先确认 ServiceAccount 注解已正确注入:

kubectl get sa karpenter -n kube-system -o yaml | grep eks.amazonaws.com/role-arn

预期输出包含 eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/KarpenterControllerRole。若为空,说明 Helm 安装时未设置 serviceAccount.annotations,需要重新配置。

然后查看控制器日志,确认没有权限错误:

kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter --tail=100

正常日志中不应出现 AccessDenied、UnauthorizedOperation 或 InvalidIdentityToken。若出现,按 SVG 中的排查判断区逐项对照。

最后用一次真实的扩容触发来验证权限闭环:提交一个资源请求较大的 Pod,观察 Karpenter 是否能成功调用 RunInstances 并创建节点。若节点成功加入集群,说明 IRSA 链路与权限策略均已生效。

常见陷阱:信任策略中的 sub 条件必须与 ServiceAccount 的命名空间和名称完全一致。如果 Karpenter 安装在 karpenter 命名空间而非 kube-system,而信任策略仍写 system:serviceaccount:kube-system:karpenter,STS 会拒绝 AssumeRole,日志中表现为 InvalidIdentityToken 或 AccessDenied。