我正在尝试通过Kinesis Firehose将AWS cloudwatch日志流式传输到ES。下面的terraform代码给出了一个错误。有什么建议么..
错误是:
resource "aws_s3_bucket" "bucket" {
bucket = "cw-kinesis-es-bucket"
acl = "private"
}
resource "aws_iam_role" "firehose_role" {
name = "firehose_test_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "firehose.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_elasticsearch_domain" "es" {
domain_name = "firehose-es-test"
elasticsearch_version = "1.5"
cluster_config {
instance_type = "t2.micro.elasticsearch"
}
ebs_options {
ebs_enabled = true
volume_size = 10
}
advanced_options {
"rest.action.multi.allow_explicit_index" = "true"
}
access_policies = <<CONFIG
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "es:*",
"Principal": "*",
"Effect": "Allow",
"Condition": {
"IpAddress": {"aws:SourceIp": ["xxxxx"]}
}
}
]
}
CONFIG
snapshot_options {
automated_snapshot_start_hour = 23
}
tags {
Domain = "TestDomain"
}
}
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"
}
}
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_cloudwatch_log_subscription_filter" "test_kinesis_logfilter" {
name = "test_kinesis_logfilter"
role_arn = "${aws_iam_role.iam_for_lambda.arn}"
log_group_name = "loggorup.log"
filter_pattern = ""
destination_arn = "${aws_kinesis_firehose_delivery_stream.test_stream.arn}"
}
最佳答案
在此配置中,您将指示Cloudwatch Logs将日志记录发送到Kinesis Firehose,后者又被配置为将接收到的数据写入S3和ElasticSearch。因此,您正在使用的AWS服务按以下方式彼此交谈:
为了使一个AWS服务与另一个服务进行对话,第一个服务必须承担一个角色,以授予其访问权限。在IAM术语中,“承担角色”是指以授予该角色的特权临时执行操作。 AWS IAM角色包含两个关键部分:
这里需要两个单独的角色。一个角色将授予Cloudwatch Logs与Kinesis Firehose对话的权限,而第二个角色将授予Kinesis Firehose与S3和ElasticSearch对话的权限。
对于此答案的其余部分,我将假定Terraform以具有对AWS账户的完全管理访问权限的用户身份运行。如果不是这样,则首先必须确保Terraform以IAM主体的身份运行,并且有权创建和传递角色。
访问Cloudwatch日志到Kinesis Firehose
在问题给出的示例中,
aws_cloudwatch_log_subscription_filter
具有一个role_arn
,其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服务访问任何Kinesis Firehose操作的调用,只要它以该Terraform配置创建的特定交付流为目标即可。这比严格需要的更多。有关更多信息,请参见Actions and Condition Context Keys for 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 Delivery Stream启用了日志记录,否则非常重要,否则Kinesis Firehose无法将日志写回到Cloudwatch Logs。
同样,这比严格需要的更多。有关支持的特定操作的更多信息,请参见以下引用:
由于此单一角色有权写入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
或firehose.amazonaws.com
。不幸的是,这些文件通常没有很好的文档记录,很难找到,但是通常可以在每个服务的用户指南中的策略示例中找到。 关于amazon-web-services - 用于连接AWS Cloudwatch日志,Kinesis Firehose,S3和ElasticSearch的AWS IAM策略,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43947159/