精通 AWS 跨账户 Secrets 与 Terraform & KMS

发布: (2025年12月3日 GMT+8 22:05)
4 min read
原文: Dev.to

Source: Dev.to

多账户现实检查

在现代云架构中,多账户策略已成为常态。我们将开发环境与生产环境分离,并且常常将共享服务集中到自己的中心。

一个非常常见的场景是,在中心的 SecurityShared Services AWS 账户中使用 AWS Secrets Manager 保存敏感的数据库凭证,而这些凭证需要被运行在完全不同的 Workload 账户中的 Lambda 函数访问。

纸面上看起来很简单:

  1. 在账户 A 中创建密钥。
  2. 为密钥附加资源策略,允许账户 B 读取它。
  3. 为账户 B 中的 Lambda 授予读取密钥的 IAM 权限。

你部署 Terraform,调用 Lambda,结果……失败。出现 AccessDeniedException 或模糊的 KMS 错误。

在调试 Secrets Manager(或 S3、SQS)跨账户访问失败时,90 % 的时间开发者会关注 IAM 策略。但当涉及密钥时,你实际上在进行两线作战:身份验证(IAM)加密(KMS)

默认情况下,如果在 Secrets Manager 中创建密钥时未指定加密设置,AWS 会使用该服务的 AWS‑托管密钥(alias/aws/secretsmanager)进行加密。

陷阱在此: 你无法修改 AWS‑托管密钥的密钥策略。它只能信任同一账户内的主体。无论你的 IAM 策略多么宽松,外部账户都永远无法解密负载。门是打开的,但盒子已经焊死。

要实现跨账户访问,必须自行控制加密。创建一个 客户托管密钥(CMK) 并显式信任外部账户。

Terraform 实现

变量和数据源

variable "external_consumer_account_id" {
  description = "The AWS Account ID that needs read access to the secrets."
  type        = string
  # Example: "123456789012"
}

# Helper to get current account ID for policy definitions
data "aws_caller_identity" "current" {}

KMS 密钥和别名

resource "aws_kms_key" "cross_account_secrets_key" {
  description             = "KMS Key for cross-account RDS credentials"
  deletion_window_in_days = 30
  enable_key_rotation     = true

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "EnableIAMUserPermissionsForCurrentAccount"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
        Action   = "kms:*"
        Resource = "*"
      },
      {
        Sid    = "AllowExternalAccountToDecrypt"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${var.external_consumer_account_id}:root"
        }
        Action = [
          "kms:Decrypt",
          "kms:DescribeKey"
        ]
        Resource = "*"
      }
    ]
  })
}

resource "aws_kms_alias" "secrets_key_alias" {
  name          = "alias/cross-account-secrets-key"
  target_key_id = aws_kms_key.cross_account_secrets_key.key_id
}

Secrets Manager 密钥

resource "aws_secretsmanager_secret" "database_credentials" {
  name        = "prod/rds/read-replica-creds"
  description = "Database credentials accessible by workload accounts"

  # CRITICAL: Force the use of our custom KMS key
  kms_key_id = aws_kms_key.cross_account_secrets_key.id
}

密钥资源策略

resource "aws_secretsmanager_secret_policy" "database_credentials_policy" {
  secret_arn = aws_secretsmanager_secret.database_credentials.arn

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "AllowExternalRead"
        Effect    = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${var.external_consumer_account_id}:root"
        }
        Action   = "secretsmanager:GetSecretValue"
        Resource = "*"
      }
    ]
  })
}

必要的权限

要成功进行跨账户密钥检索,需要同时打开三道门:

  1. KMS 密钥策略(源账户)必须信任目标账户的 Decrypt 权限。
  2. 密钥资源策略(源账户)必须信任目标账户的 GetSecretValue 权限。
  3. 附加在 Lambda/EC2 上的 IAM 角色(目标账户)必须拥有对相应 ARN 执行上述两项操作的权限。

使用默认的 AWS 密钥是多账户架构中最常见的陷阱。通过转向客户托管密钥并在 Terraform 中显式处理策略定义,你可以确保跨账户访问既安全又可重复。

Back to Blog

相关文章

阅读更多 »

Terraform 项目:简单 EC2 + 安全组

项目结构 terraform-project/ │── main.tf │── variables.tf │── outputs.tf │── providers.tf │── terraform.tfvars │── modules/ │ └── ec2/ │ ├── main.tf │ …

在 S3 中保存 Terraform 状态

配置 S3 作为 Terraform 后端 Terraform 可以将其状态存储在 S3 存储桶中。以下是一个最小的配置示例,用于设置 S3 后端:hcl terrafor...