如何让Terraform创建的AWS实例配置文件具备SSM读取及KMS解密权限?
问题背景
我正在搭建一个IAM实例配置文件,让EC2实例能读取SSM参数存储中的加密密钥并通过关联的KMS密钥解密。目前已经完成了仅具备SSM参数读取权限的配置,但缺少解密权限,运行Python客户端调用GetParameters时出现以下错误:
botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the GetParameters operation: User: arn:aws:sts::983867311419:assumed-role/ssm_read_role/i-095049df3e5cs1947 is not authorized to perform: kms:Decrypt on resource: arn:aws:kms:us-west-1:983867311419:key/f460e94d-5655-4297-89ae-feha7s81jar8 because no identity-based policy allows the kms:Decrypt action (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: a25d9846-448a-422e-bdb6-5f12af368790; Proxy: null)
之前尝试过两种错误方法:
- 把
kms:Decrypt添加到信任策略(ec2_ssm_read_role_assume_policy.json)中,因信任策略仅处理STS角色扮演逻辑,报错; - 创建自定义
kms:Decrypt策略时用了aws_iam_role_policy资源,然后试图通过aws_iam_role_policy_attachment关联,出现属性错误:
│ Error: Unsupported attribute
│
│ on main.tf line 44, in resource "aws_iam_role_policy_attachment" "kms_decrypt_policy_attachment":
│ 44: policy_arn = aws_iam_role_policy.kms_decrypt_policy.arn
│
│ This object has no argument, nested block, or exported attribute named "arn".
现有代码
main.tf
# main.tf provider "aws" { region = var.aws_config.region } # Create an IAM role resource "aws_iam_role" "ssm_read_role" { name = var.iam_ssm_read_config.role_name assume_role_policy = file("iam/ec2_ssm_read_role_assume_policy.json") } # Attach AmazonSSMReadOnlyAccess policy to the IAM role resource "aws_iam_role_policy_attachment" "ssm_policy_attachment" { policy_arn = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess" role = aws_iam_role.ssm_read_role.name } # Create a EC2 profile of for assuming the role resource "aws_iam_instance_profile" "ssm_read_profile" { name = var.iam_ssm_read_config.profile_name role = aws_iam_role.ssm_read_role.name } output "iam_role_arn" { value = aws_iam_role.ssm_read_role.arn } output "iam_role_name" { value = aws_iam_role.ssm_read_role.name } output "iam_profile_name" { value = aws_iam_instance_profile.ssm_read_profile.name }
iam/ec2_ssm_read_role_assume_policy.json
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" } } }
正确实现方法
核心说明
- 信任策略(
assume_role_policy)仅用于定义谁能扮演这个角色(这里是EC2服务),不能添加权限策略; aws_iam_role_policy是内联策略,直接附着在角色上,没有独立ARN,不能用aws_iam_role_policy_attachment关联;如果要用attachment,需要创建独立的托管策略(aws_iam_policy)。
下面提供两种可行方案:
方案一:使用内联策略直接添加解密权限
在main.tf中新增aws_iam_role_policy资源,直接给角色附加KMS解密权限:
# 新增:给SSM读取角色添加KMS解密权限(内联策略) resource "aws_iam_role_policy" "kms_decrypt_policy" { name = "kms-decrypt-for-ssm-params" role = aws_iam_role.ssm_read_role.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "kms:Decrypt" Resource = "arn:aws:kms:us-west-1:983867311419:key/f460e94d-5655-4297-89ae-feha7s81jar8" # 替换为你的KMS密钥ARN } ] }) }
方案二:创建独立托管策略再附加
先创建独立的IAM托管策略,再通过aws_iam_role_policy_attachment关联到角色:
# 新增:创建独立的KMS解密托管策略 resource "aws_iam_policy" "kms_decrypt_policy" { name = "KMS-Decrypt-For-SSM-Params" description = "Allow decrypting SSM parameters using specific KMS key" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "kms:Decrypt" Resource = "arn:aws:kms:us-west-1:983867311419:key/f460e94d-5655-4297-89ae-feha7s81jar8" # 替换为你的KMS密钥ARN } ] }) } # 新增:将托管策略附加到SSM读取角色 resource "aws_iam_role_policy_attachment" "kms_decrypt_policy_attachment" { policy_arn = aws_iam_policy.kms_decrypt_policy.arn role = aws_iam_role.ssm_read_role.name }
权限优化建议
为了遵循最小权限原则,你可以进一步缩小权限范围:
- 如果SSM参数有特定命名前缀,可以在KMS策略的
Condition中添加限制,仅允许解密对应前缀的SSM参数触发的请求:
"Condition": { "StringEquals": { "kms:EncryptionContext:aws:ssm:parameter-name": "/your-parameter-prefix/*" } }
内容的提问来源于stack exchange,提问作者MrChadMWood

