基于AWS MFA的GitLab CI流水线认证权限问题求助
解决GitLab CI流水线推送ECR的身份认证问题
问题根源
你遇到的AccessDenied错误,核心原因有两个:
- 自托管在EC2上的GitLab Runner默认会继承EC2实例的IAM角色权限,但这个角色没有被允许调用
sts:AssumeRoleWithWebIdentity操作; - 你创建的
GitLab_Role是Web Identity类型角色,只能通过GitLab的OIDC令牌申请临时凭证,无法直接绑定给EC2实例使用。
分步解决方案
1. 给EC2实例角色添加权限
找到GitLab Runner所在EC2实例使用的IAM角色(比如命名为EC2_GitLab_Runner_Role),添加以下权限策略,允许它调用STS服务获取GitLab_Role的临时凭证:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRoleWithWebIdentity", "Resource": "arn:aws:iam::你AWS账号ID:role/GitLab_Role" } ] }
2. 修正.gitlab-ci.yml的凭证获取逻辑
不要让Runner直接用Web Identity去AssumeRole,而是先借助EC2实例角色的权限,拿GitLab的OIDC令牌申请GitLab_Role的临时凭证,再用这些凭证操作ECR。示例配置如下:
stages: - build-and-push build-ecr-image: stage: build-and-push image: docker:latest services: - docker:dind before_script: # 安装AWS CLI和jq(用于解析JSON输出) - apk add --no-cache aws-cli jq # 定义关键变量 - export AWS_ROLE_ARN="arn:aws:iam::你AWS账号ID:role/GitLab_Role" - export AWS_WEB_IDENTITY_TOKEN_FILE="/tmp/gitlab-jwt-token" # 将GitLab提供的JWT令牌写入文件 - echo "${CI_JOB_JWT_V2}" > $AWS_WEB_IDENTITY_TOKEN_FILE # 调用STS服务获取GitLab_Role的临时凭证 - | CREDS=$(aws sts assume-role-with-web-identity \ --role-arn $AWS_ROLE_ARN \ --role-session-name "gitlab-ci-${CI_JOB_ID}" \ --web-identity-token file://$AWS_WEB_IDENTITY_TOKEN_FILE) # 导出临时凭证到环境变量 - export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId') - export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey') - export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken') # 登录ECR仓库 - aws ecr get-login-password --region 你的AWS区域 | docker login --username AWS --password-stdin 你AWS账号ID.dkr.ecr.你的AWS区域.amazonaws.com script: # 构建镜像 - docker build -t 你的ECR仓库URI:${CI_COMMIT_SHORT_SHA} . # 推送镜像到ECR - docker push 你的ECR仓库URI:${CI_COMMIT_SHORT_SHA}
3. 校验GitLab_Role的信任关系
确保GitLab_Role的信任关系配置正确,仅允许你指定的GitLab项目通过OIDC访问:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::你AWS账号ID:oidc-provider/gitlab.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "gitlab.com:aud": "https://gitlab.com", "gitlab.com:sub": "project_path:你的GitLab用户名/你的项目名:*" } } } ] }
4. 确认Runner环境配置
- 自托管Runner无需额外配置AWS密钥,只要所在EC2实例拥有上述添加的权限即可;
- 确保GitLab项目中
CI_JOB_JWT_V2变量已启用(前往项目设置→CI/CD→变量,展开预定义变量确认); - 将所有占位符(如账号ID、区域、仓库URI)替换为你自己的实际信息。
关键提醒
- 遵循最小权限原则:EC2实例角色仅需拥有Assume
GitLab_Role的权限,无需直接配置ECR相关权限; - 临时凭证自带有效期,每次流水线会自动重新获取,无需手动管理过期问题;
- 若仍报错,可查看AWS CloudTrail日志,确认调用STS的角色身份及具体拒绝原因。
内容的提问来源于stack exchange,提问作者Marrsail Bailey
相关产品推荐
相关产品推荐

