You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS S3 ListObjectsV2权限拒绝求助:Github Actions部署静态网站失败

S3静态网站部署时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:54:55