精通 AWS 跨账户 Secrets 与 Terraform & KMS
Source: Dev.to
多账户现实检查
在现代云架构中,多账户策略已成为常态。我们将开发环境与生产环境分离,并且常常将共享服务集中到自己的中心。
一个非常常见的场景是,在中心的 Security 或 Shared Services AWS 账户中使用 AWS Secrets Manager 保存敏感的数据库凭证,而这些凭证需要被运行在完全不同的 Workload 账户中的 Lambda 函数访问。
纸面上看起来很简单:
- 在账户 A 中创建密钥。
- 为密钥附加资源策略,允许账户 B 读取它。
- 为账户 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 = "*"
}
]
})
}
必要的权限
要成功进行跨账户密钥检索,需要同时打开三道门:
- KMS 密钥策略(源账户)必须信任目标账户的
Decrypt权限。 - 密钥资源策略(源账户)必须信任目标账户的
GetSecretValue权限。 - 附加在 Lambda/EC2 上的 IAM 角色(目标账户)必须拥有对相应 ARN 执行上述两项操作的权限。
使用默认的 AWS 密钥是多账户架构中最常见的陷阱。通过转向客户托管密钥并在 Terraform 中显式处理策略定义,你可以确保跨账户访问既安全又可重复。