キネシスファイアホースを介してAWSクラウドウォッチログをESにストリーミングしようとしています。以下のテラフォームコードはエラーを出します。任意の提案..エラーは次のとおりです。
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>
この設定では、CloudwatchLogsにログレコードをKinesisFirehoseに送信するように指示します。これにより、受信したデータをS3とElasticSearchの両方に書き込むように設定されます。したがって、使用しているAWSサービスは次のように相互に通信しています。
あるAWSサービスが別のサービスと通信するには、最初のサービスがアクセスを許可するロールを仮定する必要があります。 IAMの用語では、「役割を引き受ける」とは、その役割に付与された特権で一時的に行動することを意味します。 AWS IAMロールには、次の2つの重要な部分があります。
ここでは、2つの別々の役割が必要です。 1つのロールはCloudwatchLogsにKinesisFirehoseと通信するためのアクセスを許可し、2番目のロールはKinesisFirehoseにS3とElasticSearchの両方と通信するためのアクセスを許可します。
この回答の残りの部分では、TerraformがAWSアカウントへの完全な管理アクセス権を持つユーザーとして実行されていると想定します。これが当てはまらない場合は、最初に、Terraformがロールの作成と受け渡しにアクセスできるIAMプリンシパルとして実行されていることを確認する必要があります。
質問の例では、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の適切な引き受け役割ポリシーを持つ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.com
やfirehose.amazonaws.com
など、リクエストを開始するサービスのサービス名。残念ながら、これらは一般的に文書化が不十分で見つけるのが困難ですが、通常、各サービスのユーザーガイド内のポリシーの例で見つけることができます。