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

2022.04.05

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

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

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

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

コード内容

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"を取得)

AWSアカウントID

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

プレフィックス

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

バケット名

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

終わりに

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

ちなみに俺はCloudFormationでバケットポリシー書きたいんだ!という人は、以下の記事も参照してみて下さい!

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