Terraform动态创建AWS MSK IAM策略并关联对应已有IAM角色的问题
Terraform 动态绑定AWS MSK IAM权限策略到应用IAM角色实现方案
背景说明
AWS MSK支持基于IAM的身份认证,但不支持S3那样的资源级策略,因此需要动态生成对应权限策略并绑定到对应应用的已有IAM角色上。假设存在两个应用:使用IAM_Role1的Application1为生产者,使用IAM_Role2的Application2为消费者。
权限策略示例
生产者权限策略
{ "Version": "2012-10-17", "Statement": [ { "sid": "mskproducer_policy", "Effect": "Allow", "Action": [ "kafka-cluster:Connect", "kafka-cluster:DescribeTopic", "kafka-cluster:WriteData" ], "Resource": "arn:aws:kafka:${var.region}:${data.aws_caller_identity.current.account_id}:topic/${var.cluster_name}/*/${topic-name}" } ] }
消费者权限策略
{ "Version": "2012-10-17", "Statement": [ { "sid": "mskconsumer_policy", "Effect": "Allow", "Action": [ "kafka-cluster:Connect", "kafka-cluster:DescribeTopic", "kafka-cluster:ReadData" ], "Resource": "arn:aws:kafka:${var.region}:${data.aws_caller_identity.current.account_id}:topic/${var.cluster_name}/*/${topic-name}" } ] }
输入变量结构
variable "topic_permissions" { type = list(any) default = [ { "app_iamrole" = "iam-role-1" "producer" = ["topic3"] "consumer" = ["topic4"] }, { "app_iamrole" = "iam-role-2" "producer" = ["topic5"] "consumer" = ["topic6"] } ] }
已尝试方案的问题
- 使用Terraform的
data "aws_iam_policy_document"结合dynamic "statement"块可生成对应生产者、消费者策略并输出ARN,但无法动态将生成的策略ARN与对应IAM角色通过resource "aws_iam_role_policy_attachment"完成绑定。 - 采用内嵌策略方案,使用
resource "aws_iam_role_policy",无法将动态生成的策略作为内嵌策略绑定到对应IAM角色。 - 通过bash或Python脚本生成动态策略JSON,配合Terraform的
data "external"调用后在resource "aws_iam_role_policy"中循环使用,但执行terraform apply时报错:
Error: command "python" produced invalid JSON: json: cannot unmarshal object into Go value of type string
单独运行Python脚本输出的JSON经jsonlint校验无问题,当前使用的Terraform版本为0.13。
最终实现方案
使用aws_iam_role_policy配合for_each+aws_iam_policy_document动态生成每个角色的专属内嵌策略即可实现,完全兼容Terraform 0.13版本,无需依赖外部脚本。
步骤1:定义基础依赖数据源
data "aws_caller_identity" "current" {} data "aws_region" "current" {} variable "cluster_name" { type = string description = "MSK集群名称" }
步骤2:动态生成每个角色的权限策略文档
data "aws_iam_policy_document" "msk_topic_policy" { for_each = { for perm in var.topic_permissions : perm.app_iamrole => perm } # 批量生成生产者权限规则 dynamic "statement" { for_each = each.value.producer content { sid = "msk_producer_${replace(statement.value, "-", "_")}" effect = "Allow" action = [ "kafka-cluster:Connect", "kafka-cluster:DescribeTopic", "kafka-cluster:WriteData" ] resource = "arn:aws:kafka:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:topic/${var.cluster_name}/*/${statement.value}" } } # 批量生成消费者权限规则 dynamic "statement" { for_each = each.value.consumer content { sid = "msk_consumer_${replace(statement.value, "-", "_")}" effect = "Allow" action = [ "kafka-cluster:Connect", "kafka-cluster:DescribeTopic", "kafka-cluster:ReadData" ] resource = "arn:aws:kafka:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:topic/${var.cluster_name}/*/${statement.value}" } } }
步骤3:绑定策略到对应IAM角色
resource "aws_iam_role_policy" "msk_topic_access" { for_each = data.aws_iam_policy_document.msk_topic_policy name = "msk-topic-access-${each.key}" role = each.key # 如果传入的是IAM角色ARN,直接赋值即可,该参数同时支持名称和ARN policy = each.value.json }
方案说明
- 完全原生Terraform实现,避免了external数据源的类型解析问题(之前脚本方案报错是因为external数据源要求输出JSON的键值必须均为字符串,不能直接返回嵌套的策略对象,需要把策略序列化为字符串作为某个键的值,Terraform侧再用
jsondecode解析即可,不过原生方案稳定性更高) - 每个角色对应一个独立的内嵌策略,自动合并同一角色下所有生产者、消费者权限,不会产生多余的托管策略
- 权限变更时自动更新对应角色的策略,无需手动调整
内容的提问来源于stack exchange,提问作者dilsingi
相关产品推荐
相关产品推荐

