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

AWS DMS从Postgres RDS同步Redshift遇S3 AccessDenied问题

问题

我们通过Terraform部署AWS DMS复制任务,将Postgres数据库全量同步至Redshift。表已按正确Schema创建,但数据滞留在DMS用作中间环节的S3桶中,未同步至Redshift。

已按Terraform文档配置dms-access-for-endpoint、dms-cloudwatch-logs-role、dms-vpc-role三个IAM角色(部署在独立栈,且被另一个正常运行的DMS实例使用),IAM配置代码如下:

data "aws_iam_policy_document" "dms_assume_role_document" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      identifiers = [
        "s3.amazonaws.com",
        "iam.amazonaws.com",
        "redshift.amazonaws.com",
        "dms.amazonaws.com",
        "redshift-serverless.amazonaws.com"
      ]
      type        = "Service"
    }
  }
}

# Database Migration Service requires the below IAM Roles to be created before
# replication instances can be created. See the DMS Documentation for
# additional information: https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Security.html#CHAP_Security.APIRole
#  * dms-vpc-role
#  * dms-cloudwatch-logs-role
#  * dms-access-for-endpoint
resource "aws_iam_role" "dms_access_for_endpoint" {
  name                  = "dms-access-for-endpoint"
  assume_role_policy    = data.aws_iam_policy_document.dms_assume_role_document.json
  managed_policy_arns   = ["arn:aws:iam::aws:policy/service-role/AmazonDMSRedshiftS3Role"]
  force_detach_policies = true
}

resource "aws_iam_role" "dms_cloudwatch_logs_role" {
  name                  = "dms-cloudwatch-logs-role"
  description           = "Allow DMS to manage CloudWatch logs."
  assume_role_policy    = data.aws_iam_policy_document.dms_assume_role_document.json
  managed_policy_arns   = ["arn:aws:iam::aws:policy/service-role/AmazonDMSCloudWatchLogsRole"]
  force_detach_policies = true
}

resource "aws_iam_role" "dms_vpc_role" {
  name                  = "dms-vpc-role"
  description           = "DMS IAM role for VPC permissions"
  assume_role_policy    = data.aws_iam_policy_document.dms_assume_role_document.json
  managed_policy_arns   = ["arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole"]
  force_detach_policies = true
}

运行时CloudWatch日志报错:

2022-09-01T16:51:38 [SOURCE_UNLOAD   ]E:  Not retriable error: <AccessDenied> Access Denied [1001705]  (anw_retry_strategy.cpp:118)
2022-09-01T16:51:38 [SOURCE_UNLOAD   ]E:  Failed to list bucket 'dms-sandbox-redshift-intermediate-storage': error code <AccessDenied>: Access Denied [1001713]  (s3_dir_actions.cpp:105)
2022-09-01T16:51:38 [SOURCE_UNLOAD   ]E:  Failed to list bucket 'dms-sandbox-redshift-intermediate-storage' [1001713]  (s3_dir_actions.cpp:209)

S3服务器访问日志显示(已匿名化):

<id> dms-sandbox-redshift-intermediate-storage [01/Sep/2022:15:43:32 +0000] 10.128.69.80 arn:aws:sts::<account>:assumed-role/dms-access-for-endpoint/dms-session-for-replication-engine <code> REST.GET.BUCKET - "GET /dms-sandbox-redshift-intermediate-storage?delimiter=%2F&max-keys=1000 HTTP/1.1" 403 AccessDenied 243 - 30 - "-" "aws-sdk-cpp/1.8.80/S3/Linux/4.14.276-211.499.amzn2.x86_64 x86_64 GCC/4.9.3" - <code> SigV4 ECDHE-RSA-AES128-GCM-SHA256 AuthHeader s3.eu-west-2.amazonaws.com TLSv1.2 -

尝试为S3桶添加桶策略但未生效,配置代码如下:

resource "aws_s3_bucket" "dms_redshift_intermediate" {
  # Prefixed with `dms-` as that's what the AmazonDMSRedshiftS3Role policy filters on
  bucket = "dms-sandbox-redshift-intermediate-storage"
}

resource "aws_s3_bucket_logging" "log_bucket" {
  bucket        = aws_s3_bucket.dms_redshift_intermediate.id
  target_bucket = aws_s3_bucket.log_bucket.id
  target_prefix = "log/"
}

resource "aws_s3_bucket" "log_bucket" {
  bucket = "${aws_s3_bucket.dms_redshift_intermediate.id}-logs"
}

resource "aws_s3_bucket_acl" "log_bucket" {
  bucket = aws_s3_bucket.log_bucket.id
  acl    = "log-delivery-write"
}

resource "aws_s3_bucket_policy" "dms_redshift_intermediate_policy" {
  bucket = aws_s3_bucket.dms_redshift_intermediate.id
  policy = data.aws_iam_policy_document.dms_redshift_intermediate_policy_document.json
}

data "aws_iam_policy_document" "dms_redshift_intermediate_policy_document" {
  statement {
    actions = [
      "s3:*"
    ]

    principals {
      identifiers = [
        "dms.amazonaws.com",
        "redshift.amazonaws.com"
      ]
      type = "Service"
    }

    resources = [
      aws_s3_bucket.dms_redshift_intermediate.arn,
      "${aws_s3_bucket.dms_redshift_intermediate.arn}/*"
    ]
  }
}

DMS可将加密CSV文件PUT至S3桶,但无法GET文件同步至Redshift,需解决该问题实现数据同步。


解决方案

1. 修正S3桶策略的授权主体

当前桶策略授权的是服务主体,但日志显示是dms-access-for-endpoint角色的会话发起请求,需直接授权该IAM角色:

data "aws_iam_policy_document" "dms_redshift_intermediate_policy_document" {
  statement {
    actions = [
      "s3:ListBucket",
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject"
    ]

    principals {
      identifiers = ["arn:aws:iam::<your-account-id>:role/dms-access-for-endpoint"]
      type        = "AWS"
    }

    resources = [
      aws_s3_bucket.dms_redshift_intermediate.arn,
      "${aws_s3_bucket.dms_redshift_intermediate.arn}/*"
    ]
  }
}

2. 补充IAM角色的S3权限

AmazonDMSRedshiftS3Role托管策略可能缺少ListBucket等必要权限,为dms-access-for-endpoint添加自定义补充策略:

resource "aws_iam_policy" "dms_s3_supplemental" {
  name        = "dms-s3-supplemental-policy"
  description = "补充DMS访问S3桶的必要权限"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:ListBucket",
          "s3:GetObject"
        ]
        Effect   = "Allow"
        Resource = [
          aws_s3_bucket.dms_redshift_intermediate.arn,
          "${aws_s3_bucket.dms_redshift_intermediate.arn}/*"
        ]
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "dms_s3_supplemental_attach" {
  role       = aws_iam_role.dms_access_for_endpoint.name
  policy_arn = aws_iam_policy.dms_s3_supplemental.arn
}

3. 精简IAM角色的信任策略

dms-access-for-endpoint只需要允许DMS服务扮演,移除不必要的服务主体:

data "aws_iam_policy_document" "dms_assume_role_document" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      identifiers = ["dms.amazonaws.com"]
      type        = "Service"
    }
  }
}

4. 检查KMS加密权限(若启用)

如果S3桶用KMS加密,需确保dms-access-for-endpoint拥有KMS密钥的解密权限:

resource "aws_iam_policy" "dms_kms_access" {
  name        = "dms-kms-decrypt-policy"
  description = "允许DMS解密S3桶的KMS加密文件"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = ["kms:Decrypt"]
        Effect   = "Allow"
        Resource = "<your-kms-key-arn>"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "dms_kms_attach" {
  role       = aws_iam_role.dms_access_for_endpoint.name
  policy_arn = aws_iam_policy.dms_kms_access.arn
}

5. 验证VPC端点策略(若使用VPC访问S3)

如果DMS部署在VPC内并通过S3 VPC端点访问桶,需确保VPC端点策略允许dms-access-for-endpoint执行ListBucket和GetObject操作。


内容的提问来源于stack exchange,提问作者philMarius

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:12:27