Terraform部署CloudWatch Logs目标策略出现参数异常错误的原因
错误信息
Error: putting CloudWatch Logs Destination Policy (exp-mgt-connect-kinesis-destination): operation error CloudWatch Logs: PutDestinationPolicy, https response error StatusCode: 400, RequestID: 9ed8bf2f-715a-49eb-aee3-b928f7a3955a, InvalidParameterException: Only one principal block is supported.
│
│ with aws_cloudwatch_log_destination_policy.destination_policy,
│ on main.tf line 128, in resource "aws_cloudwatch_log_destination_policy" "destination_policy":
│ 128: resource "aws_cloudwatch_log_destination_policy" "destination_policy"
对应Terraform代码
resource "aws_kinesis_firehose_delivery_stream" "kinesis_firehose_stream" { name = "exp-mgt-${var.s3_bucket_prefix}-delivery-stream" destination = "extended_s3" extended_s3_configuration { role_arn = aws_iam_role.firehose_role.arn bucket_arn = "arn:aws:s3:::${var.s3_bucket_name}" buffering_size = 64 prefix = var.s3_bucket_prefix } } resource "aws_iam_role" "cwl_to_firehose_role" { name = "CWLtoKinesisFirehoseRole" # Trusted entities assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { "Effect": "Allow", "Principal": { "Service": "logs.us-east-1.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }) } resource "aws_iam_role_policy" "inline_cloudwatch_policy" { name = "Permissions-Policy-For-CWL" role = aws_iam_role.cwl_to_firehose_role.id policy = jsonencode({ Version: "2012-10-17", Statement: [ { Sid: "FirehoseAccess1", Effect: "Allow", Action: "firehose:ListDeliveryStreams", Resource: "*" }, { Sid: "Passrole", Effect: "Allow", Action: "iam:PassRole", Resource: aws_iam_role.cwl_to_firehose_role.arn }, { Sid: "FirehoseAccess2", Effect: "Allow", Action: [ "firehose:DescribeDeliveryStream", "firehose:PutRecord", "firehose:PutRecordBatch" ], Resource: aws_kinesis_firehose_delivery_stream.kinesis_firehose_stream.arn } ] }) } resource "aws_cloudwatch_log_destination" "exp_mgt_destination" { name = "exp-mgt-${var.s3_bucket_prefix}-kinesis-destination" role_arn = aws_iam_role.cwl_to_firehose_role.arn target_arn = aws_kinesis_firehose_delivery_stream.kinesis_firehose_stream.arn } data "aws_iam_policy_document" "destination_policy" { statement { effect = "Allow" actions = [ "logs:PutSubscriptionFilter", ] resources = [ aws_cloudwatch_log_destination.exp_mgt_destination.arn, ] } } resource "aws_cloudwatch_log_destination_policy" "destination_policy" { destination_name = aws_cloudwatch_log_destination.exp_mgt_destination.name access_policy = data.aws_iam_policy_document.destination_policy.json }
报错原因
问题出在data "aws_iam_policy_document" "destination_policy"这个数据块:
- 你没有显式指定Principal(权限主体),Terraform的
aws_iam_policy_document在未定义Principal时,会默认添加包含当前AWS账户ID的Principal块,但生成的格式不符合CloudWatch Logs目标策略的要求。 - CloudWatch Logs的目标策略有强制限制:仅支持单个Principal块,且必须明确指定有权创建订阅过滤器的实体(比如账户根用户、IAM角色/用户,或者特定服务)。自动生成的默认Principal格式触发了AWS API的校验错误。
解决方法
修改data "aws_iam_policy_document" "destination_policy",添加明确的单个Principal块,示例如下:
# 先添加获取当前账户ID的数据源(如果需要允许当前账户操作) data "aws_caller_identity" "current" {} data "aws_iam_policy_document" "destination_policy" { statement { effect = "Allow" actions = [ "logs:PutSubscriptionFilter", ] resources = [ aws_cloudwatch_log_destination.exp_mgt_destination.arn, ] # 明确指定允许当前AWS账户根用户操作(根据你的场景调整) principals { type = "AWS" identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"] } # 如果你需要允许CloudWatch Logs服务本身操作,可替换为以下配置 # principals { # type = "Service" # identifiers = ["logs.us-east-1.amazonaws.com"] # } } }
显式定义单个Principal块后,生成的策略就能符合CloudWatch Logs的要求,解决报错问题。
内容的提问来源于stack exchange,提问作者Brian G

