在此配置中,您将指示 Cloudwatch Logs 将日志记录发送到 Kinesis Firehose,而 Kinesis Firehose 又配置为将接收到的数据写入 S3 和 ElasticSearch。因此,您正在使用的 AWS 服务之间的交互方式如下:
为了让一个 AWS 服务与另一个服务对话,第一个服务必须assume授予其执行此操作的权限的角色。在 IAM 术语中,“担任角色”意味着暂时使用授予该角色的权限进行操作。 AWS IAM 角色有两个关键部分:
- The 承担角色政策,控制哪些服务和/或用户可以承担该角色。
- 控制角色授予访问权限的策略。这决定了服务或用户在承担该角色后可以做什么。
这里需要两个独立的角色。第一个角色将授予 Cloudwatch Logs 访问权限以与 Kinesis Firehose 通信,而第二个角色将授予 Kinesis Firehose 访问权限以与 S3 和 ElasticSearch 通信。
对于本答案的其余部分,我将假设 Terraform 作为对 AWS 帐户具有完全管理访问权限的用户运行。如果情况并非如此,则首先需要确保 Terraform 作为有权创建和传递角色的 IAM 主体运行。
Cloudwatch 日志对 Kinesis Firehose 的访问
在问题给出的例子中,aws_cloudwatch_log_subscription_filter
has a role_arn
whose assume_role_policy
适用于 AWS Lambda,因此 Cloudwatch Logs 无权承担此角色。
要解决此问题,可以更改代入角色策略以使用 Cloudwatch Logs 的服务名称:
resource "aws_iam_role" "cloudwatch_logs" {
name = "cloudwatch_logs_to_firehose"
assume_role_policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "logs.us-east-1.amazonaws.com"
},
"Effect": "Allow",
"Sid": "",
},
],
})
}
上述内容允许 Cloudwatch Logs 服务承担该角色。现在该角色需要一个允许写入 Firehose Delivery Stream 的访问策略:
resource "aws_iam_role_policy" "cloudwatch_logs" {
role = aws_iam_role.cloudwatch_logs.name
policy = jsonencode({
"Statement": [
{
"Effect": "Allow",
"Action": ["firehose:*"],
"Resource": [aws_kinesis_firehose_delivery_stream.test_stream.arn],
},
],
})
}
以上授予 Cloudwatch Logs 服务访问权限以调用anyKinesis Firehose 操作,只要它针对此 Terraform 配置创建的特定传输流即可。这超出了严格必要的访问范围;有关更多信息,请参阅Amazon Kinesis Firehose 的操作和条件上下文键.
为了完成这个任务,aws_cloudwatch_log_subscription_filter
必须更新资源以引用此新角色:
resource "aws_cloudwatch_log_subscription_filter" "test_kinesis_logfilter" {
name = "test_kinesis_logfilter"
role_arn = aws_iam_role.cloudwatch_logs.arn
log_group_name = "loggorup.log"
filter_pattern = ""
destination_arn = aws_kinesis_firehose_delivery_stream.test_stream.arn
# Wait until the role has required access before creating
depends_on = aws_iam_role_policy.cloudwatch_logs
}
不幸的是,由于 AWS IAM 的内部设计,Terraform 提交策略更改后通常需要几分钟才能生效,因此有时在尝试很快使用策略创建新资源时会出现与策略相关的错误在政策本身创建之后。在这种情况下,通常只需等待 10 分钟,然后再次运行 Terraform 就足够了,此时它应该从中断处恢复并重试创建资源。
Kinesis Firehose 访问 S3 和 Amazon ElasticSearch
问题中给出的示例已经具有 IAM 角色,并且具有适合 Kinesis Firehose 的代入角色策略:
resource "aws_iam_role" "firehose_role" {
name = "firehose_test_role"
assume_role_policy = jsonencode({
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
})
}
上述内容授予 Kinesis Firehose 访问权限来承担此角色。与之前一样,该角色还需要一个访问策略来授予该角色的用户对目标 S3 存储桶的访问权限:
resource "aws_iam_role_policy" "firehose_role" {
role = aws_iam_role.firehose_role.name
policy = jsonencode({
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": [aws_s3_bucket.bucket.arn]
},
{
"Effect": "Allow",
"Action": ["es:ESHttpGet"],
"Resource": ["${aws_elasticsearch_domain.es.arn}/*"]
},
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:*:log-group:*:log-stream:*"
]
},
],
})
}
上述策略允许 Kinesis Firehose 对创建的 S3 存储桶执行任何操作、对创建的 ElasticSearch 域执行任何操作,以及将日志事件写入 Cloudwatch Logs 中的任何日志流。最后一部分并不是绝对必要的,但如果为 Firehose 传输流启用了日志记录,则非常重要,否则 Kinesis Firehose 无法将日志写回 Cloudwatch Logs。
同样,这种访问权限超出了严格必要的范围。有关支持的特定操作的更多信息,请参阅以下参考文献:
- Amazon S3 的操作和上下文键
- 授予 Firehose 对 Amazon Elasticsearch Service 目标的访问权限
由于该单一角色有权写入 S3 和 ElasticSearch,因此可以在 Kinesis Firehose 传输流中为这两种传输配置指定它:
resource "aws_kinesis_firehose_delivery_stream" "test_stream" {
name = "terraform-kinesis-firehose-test-stream"
destination = "elasticsearch"
s3_configuration {
role_arn = aws_iam_role.firehose_role.arn
bucket_arn = aws_s3_bucket.bucket.arn
buffer_size = 10
buffer_interval = 400
compression_format = "GZIP"
}
elasticsearch_configuration {
domain_arn = aws_elasticsearch_domain.es.arn
role_arn = aws_iam_role.firehose_role.arn
index_name = "test"
type_name = "test"
}
# Wait until access has been granted before creating the firehose
# delivery stream.
depends_on = [aws_iam_role_policy.firehose_role]
}
完成上述所有接线后,服务应该具有连接此交付管道各部分所需的访问权限。
这一通用模式适用于两个 AWS 服务之间的任何连接。每个案例所需的重要信息是:
- 将发起请求的服务的服务名称,例如
logs.us-east-1.amazonaws.com
or firehose.amazonaws.com
。不幸的是,这些内容通常记录很少并且很难找到,但通常可以在每个服务的用户指南中的策略示例中找到。
- 需要授予的操作的名称。每个服务的完整操作集可以在以下位置找到:用于 IAM 策略的 AWS 服务操作和条件上下文键。不幸的是,专门的文档which给定服务到服务集成所需的操作通常相当缺乏,但在简单的环境中(尽管有任何严格的监管要求或有关访问的组织策略),通常足以使用通配符授予对给定服务的所有操作的访问权限上面示例中使用的语法。