TerraformでAmazon OpenSearch ServiceのログのCloudWatch Logsへの出力設定を有効化する

Amazon OpenSearch ServiceのログをCloudWatch Logsに出力したい場合、Terraformでは aws_elasticsearch_domain.log_publishing_options の設定だけでなく、CloudWatch Logsのリソースポリシーの作成(aws_cloudwatch_log_resource_policy)も必要になります。
2022.02.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンサル部のとばち(@toda_kk)です。

Amazon Elasticsearch Serviceの後継サービスとなるAmazon OpenSearch Serviceでは、検索やインデックスのログをCloudWatch Logsに出力する設定が可能です。

Terraformでリソースを管理している場合でもログの出力設定を有効化できるのですが、少しわかりづらかったので方法をまとめてみました。

出力できるログ

CloudWatch Logsに出力できるログは下記の4つがあります。

  • 検索スローログ
  • インデックススローログ
  • エラーログ(アプリケーションログ)
  • 監査ログ

詳細については、AWS公式ドキュメントの下記ページをご参照ください。

Terraformサンプル

さっそくですが、Terraformでログの出力設定を有効にするサンプルコードを記載します。

resource "aws_elasticsearch_domain" "opensearch_domain" {
  domain_name           = "sample-opensearch-domain"
  elasticsearch_version = "OpenSearch_1.1"
  cluster_config {
    instance_type          = "r6g.large.elasticsearch"
    instance_count         = 3
    zone_awareness_enabled = true
    zone_awareness_config {
      availability_zone_count = 3
    }
  }
  ebs_options {
    ebs_enabled = true
    volume_type = "gp2"
    volume_size = 30
  }

  log_publishing_options {
    cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_domain_search_logs.arn
    log_type                 = "SEARCH_SLOW_LOGS"
  }
  log_publishing_options {
    cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_domain_index_logs.arn
    log_type                 = "INDEX_SLOW_LOGS"
  }
  log_publishing_options {
    cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_domain_application_logs.arn
    log_type                 = "ES_APPLICATION_LOGS"
  }
}

resource "aws_cloudwatch_log_resource_policy" "opensearch_domain_cloudwatch_logs_policy" {
  policy_name     = "opensearch-cloudwatch-logs-policy"
  policy_document = data.aws_iam_policy_document.opensearch_domain_log_publishing_iam_policy.json
}

data "aws_iam_policy_document" "opensearch_domain_log_publishing_iam_policy" {
  statement {
    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:PutLogEventsBatch",
    ]

    resources = [
      "${aws_cloudwatch_log_group.opensearch_domain_search_logs.arn}:*",
      "${aws_cloudwatch_log_group.opensearch_domain_index_logs.arn}:*",
      "${aws_cloudwatch_log_group.opensearch_domain_application_logs.arn}:*"
    ]

    principals {
      identifiers = ["es.amazonaws.com"]
      type        = "Service"
    }
  }
}

resource "aws_cloudwatch_log_group" "opensearch_domain_search_logs" {
  name = "/aws/OpenSearchService/domains/sample-opensearch-domain/search-logs"
}

resource "aws_cloudwatch_log_group" "opensearch_domain_index_logs" {
  name = "/aws/OpenSearchService/domains/sample-opensearch-domain/index-logs"
}

resource "aws_cloudwatch_log_group" "opensearch_domain_application_logs" {
  name = "/aws/OpenSearchService/domains/sample-opensearch-domain/application-logs"
}

terraform applyを実行すると、下記のような設定でOpenSearchドメインが作成されます。

必要になるTerraformリソース

  • aws_elasticsearch_domain.log_publishing_options
  • aws_cloudwatch_log_resource_policy
  • aws_cloudwatch_log_group(ロググループが未作成の場合のみ)

aws_elasticsearch_domain.log_publishing_options

2022年2月現在、TerraformでOpenSearchドメインを作成する際はaws_elasticsearch_domainリソースを利用します。elasticsearch_versionOpenSearch_X.Yという形式でバージョンを指定することで、OpenSearchとして作成できます。

log_publishing_optionsを指定することで、ログをCloudWatch Logsに出力する設定を有効化できます。ログのタイプ、および出力先となるロググループのARNが必須項目です。

  log_publishing_options {
    cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_domain_search_logs.arn
    log_type                 = "SEARCH_SLOW_LOGS"
  }

aws_cloudwatch_log_resource_policy

加えて、CloudWatch Logsのリソースポリシーが必要になります。

上記のサンプルでは1つのリソースポリシーで複数のロググループへの出力を許可していましたが、ロググループごとにリソースポリシーを作成して出力を許可することも可能です。

resource "aws_cloudwatch_log_resource_policy" "opensearch_domain_search_logs_cloudwatch_logs_policy" {
  policy_name     = "OpenSearchService-sample-opensearch-domain-Search-logs"
  policy_document = data.aws_iam_policy_document.opensearch_domain_search_logs_publishing_iam_policy.json
}
data "aws_iam_policy_document" "opensearch_domain_search_logs_publishing_iam_policy" {
  statement {
    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:PutLogEventsBatch",
    ]
    resources = [
      "${aws_cloudwatch_log_group.opensearch_domain_search_logs.arn}:*"
    ]
    principals {
      identifiers = ["es.amazonaws.com"]
      type        = "Service"
    }
  }
}

resource "aws_cloudwatch_log_resource_policy" "opensearch_domain_index_logs_cloudwatch_logs_policy" {
  policy_name     = "OpenSearchService-sample-opensearch-domain-Index-logs"
  policy_document = data.aws_iam_policy_document.opensearch_domain_index_logs_publishing_iam_policy.json
}
data "aws_iam_policy_document" "opensearch_domain_index_logs_publishing_iam_policy" {
  statement {
    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:PutLogEventsBatch",
    ]
    resources = [
      "${aws_cloudwatch_log_group.opensearch_domain_index_logs.arn}:*"
    ]
    principals {
      identifiers = ["es.amazonaws.com"]
      type        = "Service"
    }
  }
}

resource "aws_cloudwatch_log_resource_policy" "opensearch_domain_application_logs_cloudwatch_logs_policy" {
  policy_name     = "OpenSearchService-sample-opensearch-domain-Application-logs"
  policy_document = data.aws_iam_policy_document.opensearch_domain_application_logs_publishing_iam_policy.json
}
data "aws_iam_policy_document" "opensearch_domain_application_logs_publishing_iam_policy" {
  statement {
    actions = [
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:PutLogEventsBatch",
    ]
    resources = [
      "${aws_cloudwatch_log_group.opensearch_domain_application_logs.arn}:*"
    ]
    principals {
      identifiers = ["es.amazonaws.com"]
      type        = "Service"
    }
  }
}

AUDIT_LOGSの有効化について

なお、今回は省いて記述したログタイプAUDIT_LOGS(監査ログ)については「きめ細やかなアクセスコントロール」を有効にしている場合のみログ出力設定を有効化できます。

この「きめ細やかなアクセスコントロール」の有効化について、Terraformではadvanced_security_optionsとしてサポートされています。

参考

以上、コンサル部のとばち(@toda_kk)でした。