ALBのアクセスログ用S3バケットポリシーをTerraformで書いてみた

2022.04.05

こんにちは!この前ついにドラム式洗濯機を大人買いしてしまったつくぼしです!  

ALBにアクセスログを設定したい場合、ALBがS3にアクセスできるようにバケットポリシーを書き換える必要があります。

この書き換えをTerraformで実施する場合、各々の環境毎にバケットポリシー用のjsonファイルを用意しても良いのですが、どの環境でも使用できる汎用的なバケットポリシーをtfファイルで作成してみました。

環境

$ terraform -v

Terraform v1.1.7
on darwin_arm64

対象バケットポリシー

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::elb-account-id:root"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::bucket-name/prefix/AWSLogs/your-aws-account-id/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "delivery.logs.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::bucket-name/prefix/AWSLogs/your-aws-account-id/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "delivery.logs.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::bucket-name"
    }
  ]
}

以下の公式ページに記載があります。

公式:Application Load Balancer のアクセスログ

コード内容

main.tf

#ELBアカウントIDの取得
data "aws_elb_service_account" "tf_elb_service_account" {}

#AWSアカウントIDの取得
data "aws_caller_identity" "tf_caller_identity" {}

#ALBログ用プレフィックスの設定
variable "alb_log_prefix" {
  default = "xxxxxxxxxxxxxxxxxxxx" #任意の名前
}

#ALBログ用バケット名の設定
variable "bucket_name_alb_log" {
  default = "xxxxxxxxxxxxxxxxxxxx" #任意の名前
}

#ALBログ用バケットの作成
resource "aws_s3_bucket" "tf_bucket_alb_log" {
  bucket  = "${var.bucket_name_alb_log}-${data.aws_caller_identity.tf_caller_identity.account_id}"
}

#ALBログ用バケットポリシーの作成
data "aws_iam_policy_document" "tf_iam_policy_document_alb_log" {
  statement {
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_elb_service_account.tf_elb_service_account.id}:root"]
    }
    actions   = ["s3:PutObject"]
    resources = ["arn:aws:s3:::${aws_s3_bucket.tf_bucket_alb_log.bucket}/${var.alb_log_prefix}/AWSLogs/${data.aws_caller_identity.tf_caller_identity.account_id}/*"]
  }

  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["delivery.logs.amazonaws.com"]
    }
    actions   = ["s3:PutObject"]
    resources = ["arn:aws:s3:::${aws_s3_bucket.tf_bucket_alb_log.bucket}/${var.alb_log_prefix}/AWSLogs/${data.aws_caller_identity.tf_caller_identity.account_id}/*"]
    condition {
      test     = "StringEquals"
      variable = "s3:x-amz-acl"
      values   = ["bucket-owner-full-control"]
    }
  }

  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["delivery.logs.amazonaws.com"]
    }
    actions   = ["s3:GetBucketAcl"]
    resources = ["arn:aws:s3:::${aws_s3_bucket.tf_bucket_alb_log.bucket}"]
  }
}

#バケットポリシーの書き換え
resource "aws_s3_bucket_policy" "tf_bucket_policy_alb_log" {
  bucket = aws_s3_bucket.tf_bucket_alb_log.id
  policy = data.aws_iam_policy_document.tf_iam_policy_document_alb_log.json
}

解説

ELBアカウントID

公式バケットポリシーのelb-account-idに該当する、リージョンに応じたELBのアカウントIDです。
Terraformではaws_elb_service_accountというData Sourceを用いて、ELBアカウントIDをリージョン毎に動的に取得可能です!
原則AWS Provider設定のregionに指定している値に応じて、対応するELBアカウントIDを取得できます。 (例:ap-northeast-1→ELBアカウントID"582318560864"を取得)

Data Source: aws_elb_service_account

AWSアカウントID

公式バケットポリシーのyour-aws-account-idに該当する、自身のAWSアカウントIDです。
Terraformではaws_caller_identityというData Sourceを用いて、AWSアカウントIDも取得可能です。

Data Source: aws_caller_identity

プレフィックス

公式バケットポリシーのprefixに該当する、ALBログ用バケットの階層です。
今回はInput Variablesを用いて、任意の値を指定できるようにしました。

バケット名

公式バケットポリシーのbucket-nameに該当する、ALBログ用バケットの名前です。
こちらもプレフィックスと同じく、Input Variablesで任意の値を指定できるようにしてます。
今回はInput VariablesにAWSアカウントIDを追記する事で、一意なバケット名を作成しやすくしました!

終わりに

terraformでバケットポリシーのようなjson形式の情報が必要な場合、tfファイルに組み込む事でID情報等を動的に取得できるのでオススメです!
他の環境にも流用できて便利なので、皆さんもTerraformでjsonを使用する場合はtfファイルに組み込めないか検討してみてはいかがでしょうか?

ちなみに俺はCloudFormationでバケットポリシー書きたいんだ!という人は、以下の記事も参照してみて下さい!
ALBとCLBのアクセスログを保存するS3バケットポリシーをCloudFormation(YAML)で書いてみた

以上、最近ひたすらTerraformのコードを書いているつくぼしでした!