如何在Go语言中使用Kubernetes Service Account访问AWS服务?
问题分析与解决方案
核心问题根源
你的两种写法都踩了IRSA(IAM Roles for Service Accounts)的使用误区:
- 第一种手动调用
stscreds.NewCredentials尝试AssumeRole,此时SDK默认使用节点实例角色(staging-worker-node)发起请求,而该角色没有被授权Assume你的服务账号绑定的IAM角色,因此触发AccessDenied。 - 第二种写法没有利用IRSA自动注入的凭证机制,导致SDK无法正确获取服务账号对应的权限,出现通用权限错误。
正确代码实现
IRSA会自动为Pod注入AWS_ROLE_ARN和AWS_WEB_IDENTITY_TOKEN_FILE环境变量,以及挂载临时凭证文件,aws-sdk-go(v1)会自动读取这些信息,无需手动处理凭证或AssumeRole:
package main import ( "fmt" "os" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" ) func main() { region := os.Getenv("AMAZON_REGION") if region == "" { fmt.Println("请设置AMAZON_REGION环境变量") os.Exit(1) } // 让SDK自动加载IRSA提供的凭证,无需手动指定Credentials sess, err := session.NewSession(&aws.Config{ Region: aws.String(region), }) if err != nil { fmt.Printf("创建Session失败: %v\n", err) os.Exit(1) } svc := s3.New(sess) // 示例:列出S3桶验证权限 result, err := svc.ListBuckets(nil) if err != nil { fmt.Printf("列出桶失败: %v\n", err) os.Exit(1) } fmt.Println("已授权的S3桶:") for _, b := range result.Buckets { fmt.Printf("- %s (创建时间: %s)\n", aws.StringValue(b.Name), aws.TimeValue(b.CreationDate)) } }
关键排查步骤
验证Pod内IRSA环境变量
进入Pod执行以下命令,确认环境变量存在:echo $AWS_ROLE_ARN echo $AWS_WEB_IDENTITY_TOKEN_FILE若不存在,检查K8s服务账号是否正确绑定IAM角色(查看服务账号的
eks.amazonaws.com/role-arn注解)。检查IAM角色信任策略
确保目标IAM角色(EKSServiceAccount-app)的信任策略允许你的K8s服务账号身份AssumeRole,示例策略:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::xxxxxxxx:oidc-provider/oidc.eks.<区域>.amazonaws.com/id/<OIDC_ID>" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.<区域>.amazonaws.com/id/<OIDC_ID>:sub": "system:serviceaccount:<命名空间>:<服务账号名>" } } } ] }确认IAM角色权限策略
检查角色是否包含你需要的S3操作权限(比如s3:ListBucket、s3:GetObject等),并正确指定资源范围。SDK版本验证
确保使用的aws-sdk-go版本在v1.30.0及以上,该版本开始原生支持IRSA凭证自动加载。
内容的提问来源于stack exchange,提问作者David Lima
相关产品推荐
相关产品推荐

