在 Amazon Elastic Kubernetes Service (EKS) 中部署应用程序时,经常会遇到需要与 AWS 服务交互的场景,例如使用 Amazon EBS CSI 驱动动态创建存储卷。然而,当集群配置不当或缺少关键组件时,可能会遇到类似“缺少 OpenID Connect (OIDC) 提供程序”的错误。本文以一个真实的案例为背景,深入讲解 AWS 的 aws_iam_openid_connect_provider 资源的作用、配置方法及其在 EKS 生态中的重要性。
案例背景
我在为一个生产环境部署 Apache RocketMQ 集群到 EKS 上,使用 Terraform 管理基础设施。RocketMQ 的 Broker 需要持久化存储,因此我们配置了一个 StatefulSet,通过 volumeClaimTemplates 请求 EBS 卷。然而,在运行 kubectl apply 后,pod创建遇到了以下错误:
failed to provision volume with StorageClass "gp2": rpc error: code = Internal desc = Could not create volume "pvc-34f31fa2-a30e-4e2d-ba4e-c787d39791f6": could not create volume in EC2: operation error EC2: CreateVolume, get identity: get credentials: failed to refresh cached credentials, failed to retrieve credentials, operation error STS: AssumeRoleWithWebIdentity, exceeded maximum number of attempts, 3, https response error StatusCode: 400, RequestID: cc63c0cd-155b-4053-ad62-b48c51906bc7, InvalidIdentityToken: No OpenIDConnect provider found in your account for https://oidc.eks.ap-southeast-1.amazonaws.com/id/8DE440F2238C6B959FB7C65EA52AF80B
检查后发现:
-
集群名称: prod,区域:ap-southeast-1,OIDC issuer URL:https://oidc.eks.ap-southeast-1.amazonaws.com/id/8DE440F2238C6B959FB7C65EA52AF80B。 -
AWS IAM 中没有对应的 OIDC 提供程序( aws iam list-open-id-connect-providers返回空)。 -
EBS CSI 驱动的 ServiceAccount ebs-csi-controller-sa已绑定 IAM 角色eks-ebs-csi-driver,但无法获取凭证。
问题根源在于:EKS 集群缺少 OIDC 提供程序,导致 EBS CSI 驱动无法通过 IAM Roles for Service Accounts (IRSA) 机制认证到 AWS。
什么是 aws_iam_openid_connect_provider?
aws_iam_openid_connect_provider 是 AWS IAM 中的一种资源,用于在 AWS 账户中注册一个外部身份提供者(Identity Provider, IdP),支持 OpenID Connect 协议。在 EKS 中,它的作用是将 Kubernetes 集群的 OIDC 身份提供程序与 AWS IAM 集成,从而允许 Kubernetes 服务账户通过 IRSA 扮演 IAM 角色,获取 AWS API 的临时凭证。
工作原理
EKS 集群的 OIDC Issuer:
-
每个 EKS 集群在创建时都会生成一个唯一的 OIDC issuer URL(例如 https://oidc.eks.ap-southeast-1.amazonaws.com/id/8DE440F2238C6B959FB7C65EA52AF80B)。 -
这个 URL 指向集群的 OIDC 端点,负责为服务账户生成 JWT(JSON Web Token)。 注册到 AWS IAM:
-
通过 aws_iam_openid_connect_provider,你将这个 OIDC issuer 注册到 AWS 账户中,成为一个受信任的身份提供者。 -
AWS STS(Security Token Service)会验证 JWT 是否由该 OIDC 提供程序签发。 IAM 角色绑定:
-
创建一个 IAM 角色(如 eks-ebs-csi-driver),并在信任关系中指定 OIDC 提供程序和特定的服务账户(例如system:serviceaccount:kube-system:ebs-csi-controller-sa)。 -
当服务账户所在的 Pod 发起请求时,AWS STS 会根据 JWT 颁发临时凭证。 权限执行:
-
Pod 使用这些凭证调用 AWS API,例如创建 EBS 卷。
为什么需要它?
在案例中,EBS CSI 驱动需要调用 ec2:CreateVolume API 来动态创建存储卷。由于 Terraform 创建的 prod 集群未配置 OIDC 提供程序,STS 无法验证服务账户的身份,导致认证失败。
在 Terraform 中配置 aws_iam_openid_connect_provider
由于我的集群是通过 Terraform 创建的,我们可以通过 Terraform 添加 OIDC 提供程序并修复问题。以下是具体步骤和代码。
1. 获取 EKS 集群的 OIDC Issuer
使用 data 源引用现有集群:
data "aws_eks_cluster" "prod" {
name = "prod"
}
output "oidc_issuer_url" {
value = data.aws_eks_cluster.prod.identity[0].oidc[0].issuer
}
运行后,oidc_issuer_url 应输出 https://oidc.eks.ap-southeast-1.amazonaws.com/id/8DE440F2238C6B959FB7C65EA52AF80B。
2. 创建 OIDC 提供程序
使用 aws_iam_openid_connect_provider 资源:
resource "aws_iam_openid_connect_provider" "eks_oidc" {
url = data.aws_eks_cluster.prod.identity[0].oidc[0].issuer
client_id_list = [
"sts.amazonaws.com"
]
thumbprint_list = [
"9e99a48a9960b14926bb7f3b02e22da2b0ab7280"
]
}
url:EKS 集群的 OIDC issuer URL。 client_id_list:指定允许的客户端 ID, sts.amazonaws.com是 AWS STS 的标准值。thumbprint_list:OIDC 服务器证书的根 CA 指纹,用于验证签名。 9e99...是 AWS 的默认值,通常无需更改。
3. 配置 IAM 角色
为 EBS CSI 驱动创建或更新 IAM 角色,确保信任关系指向 OIDC 提供程序:
resource "aws_iam_role" "ebs_csi_driver" {
name = "eks-ebs-csi-driver"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.eks_oidc.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"${data.aws_eks_cluster.prod.identity[0].oidc[0].issuer}:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
}
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "ebs_csi_driver_policy" {
role = aws_iam_role.ebs_csi_driver.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
}
4. 应用并验证
运行以下命令:
terraform plan -out=ftplan
terraform apply "ftplan"
完成后,检查 OIDC 提供程序:
aws --profile prod iam list-open-id-connect-providers
应返回 arn:aws:iam::140023393377:oidc-provider/oidc.eks.ap-southeast-1.amazonaws.com/id/8DE440F2238C6B959FB7C65EA52AF80B。
5. 更新 Kubernetes ServiceAccount
确保 EBS CSI 的服务账户绑定到新角色:
kubectl annotate sa ebs-csi-controller-sa -n kube-system eks.amazonaws.com/role-arn=arn:aws:iam::140023393377:role/eks-ebs-csi-driver --overwrite
修复案例中的问题
配置好 OIDC 提供程序后,重试 RocketMQ 部署:
-
删除失败的 PVC: kubectl delete pvc -n rocketmq -l app=rocketmq-broker -
重启 EBS CSI 控制器: kubectl delete pod -n kube-system -l app=ebs-csi-controller -
重新应用: kubectl apply -f rocketmq-broker.yaml -
验证: kubectl get pvc -n rocketmq
kubectl get pods -n rocketmq
如果配置正确,PVC 会成功绑定到 EBS 卷,RocketMQ 的 Broker Pod 将正常运行。
为什么 Terraform 创建的集群缺少 OIDC?
在 Terraform 中,EKS 集群默认不会自动创建 OIDC 提供程序,除非你在 aws_eks_cluster 资源创建时显式配置关联的 aws_iam_openid_connect_provider。例如:
resource "aws_eks_cluster" "example" {
name = "example-cluster"
role_arn = aws_iam_role.cluster.arn
vpc_config { ... }
}
resource "aws_iam_openid_connect_provider" "example" {
url = aws_eks_cluster.example.identity[0].oidc[0].issuer
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"]
}
在我的案例中,Terraform 配置可能只创建了集群(aws_eks_cluster),但未添加 OIDC 提供程序,导致后续 IRSA 功能失效。
替代方案:AWS Web 安装 EBS CSI
如果不想手动配置 Terraform,可以通过 AWS 管理控制台安装 EBS CSI 插件:
-
进入 EKS 集群的 Add-ons 页面。 -
添加 Amazon EBS CSI Driver,AWS 会自动创建 OIDC 提供程序和 IAM 角色。
这种方式更简单,但如果我们需要基础设施即代码(IaC)管理,Terraform 是更好的选择。
总结
aws_iam_openid_connect_provider 是 EKS 中实现 IRSA 的关键组件,连接了 Kubernetes 服务账户和 AWS IAM 角色。在案例中,由于缺少 OIDC 提供程序,EBS CSI 驱动无法认证,导致 RocketMQ 部署失败。通过 Terraform 配置 OIDC,可以快速修复问题,并为未来的 AWS 服务集成奠定基础。
无论是手动配置还是通过 AWS Web 安装,理解 OIDC 在 EKS 中的作用,能帮助我们更好地管理云原生工作负载,避免类似的认证难题。

