AWS S3 ListObjectsV2权限拒绝求助:Github Actions部署静态网站失败
aws s3 sync出现AccessDenied错误排查 我已经排查这个问题一周,翻了多篇StackOverflow帖子还是没解决。这是个基于S3的静态网站,用Terraform+Github Actions流水线部署,之前在管理账户能正常运行,但部署到开发账户时出了问题。
部署流程大部分正常,但执行aws s3 sync命令时触发如下错误:
fatal error: An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
我认为这是S3桶权限导致的问题,以下是相关代码和日志:
S3桶Terraform代码
# Main bucket for hosting web content resource "aws_s3_bucket" "static_website_s3_bucket" { bucket = var.domain_name force_destroy = true } resource "aws_s3_bucket_server_side_encryption_configuration" "static_website_s3_bucket_server_side_encryption_configuration" { bucket = aws_s3_bucket.static_website_s3_bucket.id rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } } resource "aws_s3_bucket_public_access_block" "static_website_s3_bucket_public_access_block" { depends_on = [aws_s3_bucket_versioning.static_website_s3_bucket_versioning] bucket = aws_s3_bucket.static_website_s3_bucket.id block_public_acls = false block_public_policy = false ignore_public_acls = false restrict_public_buckets = false } resource "aws_s3_bucket_versioning" "static_website_s3_bucket_versioning" { depends_on = [aws_s3_bucket_server_side_encryption_configuration.static_website_s3_bucket_server_side_encryption_configuration] bucket = aws_s3_bucket.static_website_s3_bucket.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_website_configuration" "static_website_s3_bucket_website_configuration" { bucket = aws_s3_bucket.static_website_s3_bucket.id index_document { suffix = "index.html" } error_document { key = "error.html" } } resource "aws_s3_bucket_policy" "static_website_s3_bucket_policy" { depends_on = [aws_s3_bucket_public_access_block.static_website_s3_bucket_public_access_block] bucket = aws_s3_bucket.static_website_s3_bucket.id policy = data.aws_iam_policy_document.static_website_s3_bucket_policy.json } # www bucket for redirecting to web content bucket resource "aws_s3_bucket" "static_website_s3_bucket_www" { bucket = "www.${var.domain_name}" force_destroy = true } resource "aws_s3_bucket_website_configuration" "static_website_s3_bucket_website_configuration_www" { bucket = aws_s3_bucket.static_website_s3_bucket_www.id redirect_all_requests_to { host_name = var.domain_name protocol = "https" } }
桶策略Terraform代码
data "aws_iam_policy_document" "static_website_s3_bucket_policy" { depends_on = [ aws_cloudfront_origin_access_control.static_website_cloudfront_origin_access_control, aws_s3_bucket.static_website_s3_bucket, aws_s3_bucket_public_access_block.static_website_s3_bucket_public_access_block ] statement { sid = "AllowCloudFrontServicePrincipalReadOnlyAccessToS3Bucket" effect = "Allow" actions = [ "s3:GetObject" ] resources = [ aws_s3_bucket.static_website_s3_bucket.arn, "${aws_s3_bucket.static_website_s3_bucket.arn}/*" ] principals { type = "Service" identifiers = ["cloudfront.amazonaws.com"] } condition { test = "StringEquals" variable = "AWS:SourceArn" values = [ "arn:aws:cloudfront::${var.account_id}:distribution/${aws_cloudfront_distribution.static_website_cloudfront_distribution.id}" ] } } statement { sid = "AllowS3ObjectUploads" effect = "Allow" actions = [ "s3:*" ] resources = [ aws_s3_bucket.static_website_s3_bucket.arn, "${aws_s3_bucket.static_website_s3_bucket.arn}/*" ] principals { type = "AWS" identifiers = ["arn:aws:iam::${var.account_id}:role/eit-${var.environment}-backend-terraform-role"] } } } data "aws_ssm_parameter" "static_website_cloudfront_distribution_id" { name = "${local.default_parameter_name}/cloudfront/id" } data "aws_ssm_parameter" "static_website_s3_bucket_domain_name" { name = "${local.default_parameter_name}/s3/bucket/domain_name" }
我理解桶策略需要包含两条规则:
- 允许CloudFront仅读取S3桶中的对象;
- 允许角色
eit-${var.environment}-backend-terraform-role上传对象到S3桶。
Github Actions流水线代码
name: my_name on: workflow_dispatch: permissions: id-token: write contents: read pull-requests: write jobs: development: name: my_name runs-on: ubuntu-latest env: environment: development steps: - name: Checkout Github Repository uses: actions/checkout@v3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ vars.AWS_ROLE_MANAGEMENT }} aws-region: eu-west-2 - name: my_name-development run: | echo "Deploying my_name-resume in to Development account..." echo "Remove any existing .terraform directory..." rm -Rf .terraform echo "Using role: ${{ vars.AWS_ROLE_MANAGEMENT }}" echo "Github Repository: ${{ github.repository }}" echo "Triggered by : ${{ github.triggering_actor }}" aws sts assume-role --role-arn ${{ vars.AWS_ROLE_DEVELOPMENT }} --role-session-name eit-development-backend-terraform-role echo "Running terraform init..." terraform init -reconfigure \ -backend-config="backend-config.hcl" \ -backend-config="env/website/development/backend-config.hcl" echo "Running terraform plan..." terraform plan \ -var-file="env/website/development/env.tfvars" -out tfplan.txt terraform apply tfplan.txt echo "Uploading website assets..." aws s3 sync ./website/ s3://my_name.co.uk echo "Uploading complete!"
流水线执行日志
Saved the plan to: tfplan.txt
To perform exactly these actions, run the following command to apply:
terraform apply "tfplan.txt"
Acquiring state lock. This may take a few moments...
aws_s3_bucket_policy.static_website_s3_bucket_policy: Modifying... [id=my_name.co.uk]
aws_s3_bucket_policy.static_website_s3_bucket_policy: Modifications complete after 0s [id=my_name.co.uk]Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Uploading website assets...
fatal error: An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Error: Process completed with exit code 1.
补充说明
- 为排查问题暂时关闭了Block Public Access,后续会重新开启;
- 对Github Actions不熟悉,可能配置存在问题;
- S3桶使用OAC(Origin Access Control),仅依赖桶策略。
恳请各位提供技术帮助,感谢!
内容的提问来源于stack exchange,提问作者James

