AWS CodeBuild推送镜像至ECR时出现未知用户权限错误
问题描述
我的CodeBuild无法执行构建脚本将Docker镜像推送至ECR,本地环境可正常运行,但CodeBuild中报错。错误信息如下:
denied: User: arn:aws:iam::311791021927:user/ServerlessAccount is not authorized to perform: ecr:InitiateLayerUpload on resource: arn:aws:ecr:***:014498627014:repository/squared-www because no resource-based policy allows the ecr:InitiateLayerUpload action
问题在于,用户311791021927并不存在于我的IAM或任何位置,以下是我的buildspec.yml:
version: 0.2 env: secrets-manager: DOMAIN: "squared-envs:DOMAIN" EMAIL_USERNAME: "squared-envs:EMAIL_USERNAME" EMAIL_PASSWORD: "squared-envs:EMAIL_PASSWORD" AWS_ACCESS_KEY_ID: "squared-envs:AWS_ACCESS_KEY_ID" AWS_SECRET_ACCESS_KEY: "squared-envs:AWS_SECRET_ACCESS_KEY" AWS_S3_BUCKET: "squared-envs:AWS_S3_BUCKET" AWE_REGION: "squared-envs:AWE_REGION" CLIENT_ID: "squared-envs:CLIENT_ID" HOOKDECK_AUTH_TOKEN: "squared-envs:HOOKDECK_AUTH_TOKEN" JWT_SECRECT: "squared-envs:JWT_SECRECT" KINDE_CLIENT_ID: "squared-envs:KINDE_CLIENT_ID" KINDE_CLIENT_SECRET: "squared-envs:KINDE_CLIENT_SECRET" KINDE_ISSUER_URL: "squared-envs:KINDE_ISSUER_URL" KINDE_POST_LOGIN_REDIRECT_URL: "squared-envs:KINDE_POST_LOGIN_REDIRECT_URL" KINDE_POST_LOGOUT_REDIRECT_URL: "squared-envs:KINDE_POST_LOGOUT_REDIRECT_URL" KINDE_SITE_URL: "squared-envs:KINDE_SITE_URL" MONGO_URL: "squared-envs:MONGO_URL" NEXTAUTH_SECRET: "squared-envs:NEXTAUTH_SECRET" NEXT_PUBLIC_CLIENT_ID: "squared-envs:NEXT_PUBLIC_CLIENT_ID" NEXT_PUBLIC_CONFIRM_URL: "squared-envs:NEXT_PUBLIC_CONFIRM_URL" NEXT_PUBLIC_GITHUB_CLIENT_SECRET: "squared-envs:NEXT_PUBLIC_GITHUB_CLIENT_SECRET" NEXT_PUBLIC_SERVER: "squared-envs:NEXT_PUBLIC_SERVER" NEXT_PUBLIC_URL: "squared-envs:NEXT_PUBLIC_URL" NODE_ENV: "squared-envs:NODE_ENV" PORT: "squared-envs:PORT" SEED_PASSWORD: "squared-envs:SEED_PASSWORD" GOOGLE_CLIENT_ID: "squared-envs:GOOGLE_CLIENT_ID" GOOGLE_CLIENT_SECRET: "squared-envs:GOOGLE_CLIENT_SECRET" GITHUB_CLIENT_ID: "squared-envs:GITHUB_CLIENT_ID" GITHUB_CLIENT_SECRET: "squared-envs:GITHUB_CLIENT_SECRET" phases: pre_build: commands: - echo Logging in to Amazon ECR... - aws ecr get-login-password --region $ECR_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY_URI - echo Creating .env file... - echo "DOMAIN=$DOMAIN" >> .env - echo "EMAIL_USERNAME=$EMAIL_USERNAME" >> .env - echo "EMAIL_PASSWORD=$EMAIL_PASSWORD" >> .env - echo "AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> .env - echo "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> .env - echo "AWS_S3_BUCKET=$AWS_S3_BUCKET" >> .env - echo "AWE_REGION=$AWE_REGION" >> .env - echo "CLIENT_ID=$CLIENT_ID" >> .env - echo "HOOKDECK_AUTH_TOKEN=$HOOKDECK_AUTH_TOKEN" >> .env - echo "JWT_SECRECT=$JWT_SECRECT" >> .env - echo "KINDE_CLIENT_ID=$KINDE_CLIENT_ID" >> .env - echo "KINDE_CLIENT_SECRET=$KINDE_CLIENT_SECRET" >> .env - echo "KINDE_ISSUER_URL=$KINDE_ISSUER_URL" >> .env - echo "KINDE_POST_LOGIN_REDIRECT_URL=$KINDE_POST_LOGIN_REDIRECT_URL" >> .env - echo "KINDE_POST_LOGOUT_REDIRECT_URL=$KINDE_POST_LOGOUT_REDIRECT_URL" >> .env - echo "KINDE_SITE_URL=$KINDE_SITE_URL" >> .env - echo "MONGO_URL=$MONGO_URL" >> .env - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env - echo "NEXT_PUBLIC_CLIENT_ID=$NEXT_PUBLIC_CLIENT_ID" >> .env - echo "NEXT_PUBLIC_CONFIRM_URL=$NEXT_PUBLIC_CONFIRM_URL" >> .env - echo "NEXT_PUBLIC_GITHUB_CLIENT_SECRET=$NEXT_PUBLIC_GITHUB_CLIENT_SECRET" >> .env - echo "NEXT_PUBLIC_SERVER=$NEXT_PUBLIC_SERVER" >> .env - echo "NEXT_PUBLIC_URL=$NEXT_PUBLIC_URL" >> .env - echo "NODE_ENV=$NODE_ENV" >> .env - echo "PORT=$PORT" >> .env - echo "SEED_PASSWORD=$SEED_PASSWORD" >> .env - echo Building Docker images... - DOCKER_BUILDKIT=1 docker-compose build --progress=plain build: commands: - echo Tagging Docker images... - docker tag squared-www:latest $ECR_REGISTRY_URI/squared-www:latest - docker tag squared-web:latest $ECR_REGISTRY_URI/squared-web:latest - docker tag squared-api:latest $ECR_REGISTRY_URI/squared-api:latest - docker tag squared-nginx:latest $ECR_REGISTRY_URI/squared-nginx:latest post_build: commands: - echo Pushing Docker images to Amazon ECR... - docker push $ECR_REGISTRY_URI/squared-www:latest - docker push $ECR_REGISTRY_URI/squared-web:latest - docker push $ECR_REGISTRY_URI/squared-api:latest - docker push $ECR_REGISTRY_URI/squared-nginx:latest artifacts: files: - '**/*' cache: paths: - '/var/lib/docker' - '/root/.cache/buildkit'
从服务器日志可见,所有环境变量均已正确设置,可排除该因素。我无法理解的是,这个未知用户是如何产生的?为何无法在IAM中编辑其权限(因为它并不存在)。
问题分析与解决方案
核心原因
你的buildspec.yml中通过Secrets Manager注入了AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY环境变量,这会直接覆盖CodeBuild默认使用的服务角色身份。Docker推送镜像时,实际使用的是这组密钥对应的外部IAM账号(即错误信息中的311791021927账号),而该账号没有当前ECR仓库的访问权限。本地运行正常是因为你使用的是自己有权限的本地AWS凭证,和CodeBuild里的身份完全不同。
解决步骤
方案1:使用CodeBuild默认服务角色(优先推荐)
- 从buildspec.yml的
env.secrets-manager配置中,移除AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY这两项,让CodeBuild使用默认的服务角色执行操作。 - 给CodeBuild的服务角色添加ECR相关权限:
编辑该角色的IAM策略,添加以下内容:
如果需要推送多个ECR仓库,可将资源ARN改为{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:BatchCheckLayerAvailability", "ecr:PutImage" ], "Resource": "arn:aws:ecr:***:014498627014:repository/squared-www" } ] }arn:aws:ecr:***:014498627014:repository/*以覆盖所有仓库。
方案2:必须使用外部账号密钥时
- 登录到密钥对应的311791021927账号,确认
ServerlessAccount用户存在,并给该用户添加ECR相关操作权限。 - 在当前ECR仓库的资源策略中,添加允许外部账号用户访问的规则:
{ "Version": "2008-10-17", "Statement": [ { "Sid": "AllowExternalAccountPush", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::311791021927:user/ServerlessAccount" }, "Action": [ "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:PutImage" ] } ] }
内容的提问来源于stack exchange,提问作者Jacob Sanderson
相关产品推荐
相关产品推荐

