我正在尝试通过Kinesis Firehose将AWS cloudwatch日志流式传输到ES。下面的terraform代码给出了一个错误。有什么建议么..
错误是:

  • aws_cloudwatch_log_subscription_filter.test_kinesis_logfilter:发生1个错误:
  • aws_cloudwatch_log_subscription_filter.test_kinesis_logfilter:InvalidParameterException:无法将测试消息传递到指定的Firehose流。检查给定的Firehose流是否处于ACTIVE状态。
  • 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服务按以下方式彼此交谈:

    amazon-web-services - 用于连接AWS Cloudwatch日志,Kinesis Firehose,S3和ElasticSearch的AWS IAM策略-LMLPHP

    为了使一个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。

    同样,这比严格需要的更多。有关支持的特定操作的更多信息,请参见以下引用:
  • Action and Context Keys for Amazon S3
  • Grant Firehose Access to an Amazon Elasticsearch Service Destination

  • 由于此单一角色有权写入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.comfirehose.amazonaws.com。不幸的是,这些文件通常没有很好的文档记录,很难找到,但是通常可以在每个服务的用户指南中的策略示例中找到。
  • 需要授予的操作的名称。每个服务的完整 Action 集可以在AWS Service Actions and Condition Context Keys for Use in IAM Policies中找到。再次遗憾的是,通常缺少用于特定服务到服务集成所需的具体操作的文档,但是在简单的环境中(尽管有严格的法规要求或关于访问的组织策略),通常足以授予对所有操作的访问权限给定的服务,使用上面示例中使用的通配符语法。
  • 关于amazon-web-services - 用于连接AWS Cloudwatch日志,Kinesis Firehose,S3和ElasticSearch的AWS IAM策略,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43947159/

    10-11 07:34