web-dev-qa-db-ja.com

AWS Cloudwatch Logs、Kinesis Firehose、S3、ElasticSearchを接続するためのAWSIAMポリシー

キネシスファイアホースを介してAWSクラウドウォッチログをESにストリーミングしようとしています。以下のテラフォームコードはエラーを出します。任意の提案..エラーは次のとおりです。

  • 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}"
}
</ code>
9
Bond

この設定では、CloudwatchLogsにログレコードをKinesisFirehoseに送信するように指示します。これにより、受信したデータをS3とElasticSearchの両方に書き込むように設定されます。したがって、使用しているAWSサービスは次のように相互に通信しています。

Cloudwatch Logs talks to Kinesis Firehose, which in turn talks to both S3 and ElasticSearch

あるAWSサービスが別のサービスと通信するには、最初のサービスがアクセスを許可するロールを仮定する必要があります。 IAMの用語では、「役割を引き受ける」とは、その役割に付与された特権で一時的に行動することを意味します。 AWS IAMロールには、次の2つの重要な部分があります。

  • ロールポリシーを想定します。これは、どのサービスやユーザーがロールを引き受けるかを制御します。
  • ロールがアクセスを許可する対象を制御するポリシー。これにより、サービスまたはユーザーが役割を引き受けた後に何ができるかが決まります。

ここでは、2つの別々の役割が必要です。 1つのロールはCloudwatchLogsにKinesisFirehoseと通信するためのアクセスを許可し、2番目のロールはKinesisFirehoseにS3とElasticSearchの両方と通信するためのアクセスを許可します。

この回答の残りの部分では、TerraformがAWSアカウントへの完全な管理アクセス権を持つユーザーとして実行されていると想定します。これが当てはまらない場合は、最初に、Terraformがロールの作成と受け渡しにアクセスできるIAMプリンシパルとして実行されていることを確認する必要があります。


KinesisFirehoseへのCloudwatchログへのアクセス

質問の例では、aws_cloudwatch_log_subscription_filterにはrole_arnがあります。assume_role_policyはAWSLambda用であるため、CloudwatchLogsはこのロールを引き受けるためのアクセス権を持っていません。

これを修正するには、CloudwatchLogsのサービス名を使用するようにロールの引き受けポリシーを変更できます。

resource "aws_iam_role" "cloudwatch_logs" {
  name = "cloudwatch_logs_to_firehose"
  assume_role_policy = <<EOF
  {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "logs.us-east-1.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

上記により、CloudwatchLogsサービスがその役割を引き受けることができます。ここで、ロールには、Firehose DeliveryStreamへの書き込みを許可するアクセスポリシーが必要です。

resource "aws_iam_role_policy" "cloudwatch_logs" {
  role = "${aws_iam_role.cloudwatch_logs.name}"

  policy = <<EOF
{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["firehose:*"],
      "Resource": ["${aws_kinesis_firehose_delivery_stream.test_stream.arn}"]
    }
  ]
}
EOF
}

上記は、Cloudwatch Logsサービスに、このTerraform設定によって作成された特定の配信ストリームを対象としている限り、anyKinesisFirehoseアクションを呼び出すためのアクセスを許可します。これは、厳密に必要なアクセスよりも多くのアクセスです。詳細については、 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を再度実行するだけで十分です。その時点で、中断したところから再開して、リソースの作成を再試行する必要があります。


KinesisFirehoseのS3およびAmazonElasticSearchへのアクセス

質問で与えられた例には、KinesisFirehoseの適切な引き受け役割ポリシーを持つIAM役割がすでにあります。

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
}

上記は、KinesisFirehoseにこの役割を引き受けるためのアクセスを許可します。以前と同様に、このロールには、ロールのユーザーにターゲットS3バケットへのアクセスを許可するためのアクセスポリシーも必要です。

resource "aws_iam_role_policy" "firehose_role" {
  role = "${aws_iam_role.firehose_role.name}"

  policy = <<EOF
{
  "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:*"
      ]
    }
  ]
}
EOF
}

上記のポリシーにより、Kinesis Firehoseは、作成されたS3バケットで任意のアクションを実行し、作成されたElasticSearchドメインで任意のアクションを実行し、CloudwatchLogsの任意のログストリームにログイベントを書き込むことができます。これの最後の部分は厳密には必要ありませんが、Firehose Delivery Streamでロギングが有効になっている場合、またはKinesisFirehoseがCloudwatchLogsにログを書き戻すことができない場合は重要です。

繰り返しますが、これは厳密に必要な以上のアクセスです。サポートされている特定のアクションの詳細については、次のリファレンスを参照してください。

この単一のロールはS3とElasticSearchの両方に書き込むためのアクセス権を持っているため、KinesisFirehose配信ストリームでこれらの配信構成の両方に指定できます。

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"]
}

上記の配線がすべて完了したら、サービスはこの配信パイプラインの一部を接続するために必要なアクセス権を持っている必要があります。

これと同じ一般的なパターンは、2つのAWSサービス間のすべての接続に適用されます。それぞれの場合に必要な重要な情報は次のとおりです。

  • logs.us-east-1.amazonaws.comfirehose.amazonaws.comなど、リクエストを開始するサービスのサービス名。残念ながら、これらは一般的に文書化が不十分で見つけるのが困難ですが、通常、各サービスのユーザーガイド内のポリシーの例で見つけることができます。
  • 付与する必要のあるアクションの名前。各サービスのアクションの完全なセットは、 IAMポリシーで使用するAWSサービスアクションと条件コンテキストキー にあります。残念ながら、特定のサービス間統合に必要な具体的なアクションのドキュメントは、一般的にかなり不足していますが、単純な環境では(ハードにもかかわらず)アクセスに関する規制要件または組織ポリシー)通常、上記の例で使用されているワイルドカード構文を使用して、特定のサービスのすべてのアクションへのアクセスを許可するだけで十分です。
16
Martin Atkins