はじめに
ALB(ロードバランサー)のアクセスログを S3 に保存したくて、Terraform で設定しました。
aws_lb に access_logs を1ブロック足すだけ、と思っていました。でも調べてみると、書き方を間違えると、ALB 作成時やアクセスログ有効化時に失敗することがあると分かったので、先回りで対策しました。
カギは「バケットポリシー」と「作る順番(depends_on)」の2点でした😅
環境
Terraform(AWS プロバイダ 5 系)
Application Load Balancer(ALB)+ アクセスログ用 S3
リージョン: ap-northeast-1
起きたこと(調べて先回りで気づいたこと)
最初は「access_logs を有効にすれば、ALB が勝手に S3 へ書いてくれる」と思っていました。
でも実際は、ログを S3 に書き込むには、Elastic Load Balancing のログ配信サービスに対して、S3 バケット側で書き込みを許可する必要がありました。知らずに書くと、次の2点でつまずきます。
ログ用 S3 バケットに、書き込みを許可するバケットポリシーが要る
ALB を作る前にそのポリシーが出来ていないと、作成時の書き込みチェックで失敗しうる
原因
aws_lb の access_logs を有効にすると、AWS は作成時に「本当にこのバケットへ書けるか」を確認します。
バケットポリシーがまだ無い、あるいは ALB がポリシーより先に作られると、ここで失敗します。Terraform は access_logs の「バケットID」は参照していても、「ポリシーが必要」という関係までは自動で読み取れないことがあるため、順番を明示する必要がありました。
対処
バケットポリシー(公式推奨のサービスプリンシパル方式)を作り、ALB に depends_on で「ポリシーの後に作る」と明示しました。
data "aws_caller_identity" "current" {}
ログ用バケットは ALB と同じリージョンに作る
resource "aws_s3_bucket" "logs" {
bucket = "myapp-alb-logs-xxxx"
}
アクセスログは SSE-S3(AES256)で。SSE-KMS にすると出力で詰まることがある
resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
bucket = aws_s3_bucket.logs.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
Elastic Load Balancing のログ配信サービスに、指定パスへの書き込みを許可
data "aws_iam_policy_document" "logs" {
statement {
principals {
type = "Service"
identifiers = ["logdelivery.elasticloadbalancing.amazonaws.com"]
}
actions = ["s3:PutObject"]
resources = ["${aws_s3_bucket.logs.arn}/alb/AWSLogs/${data.aws_caller_identity.current.account_id}/*"]
condition {
test = "ArnLike"
variable = "aws:SourceArn"
values = ["arn:aws:elasticloadbalancing:ap-northeast-1:${data.aws_caller_identity.current.account_id}:loadbalancer/*"]
}
}
}
resource "aws_s3_bucket_policy" "logs" {
bucket = aws_s3_bucket.logs.id
policy = data.aws_iam_policy_document.logs.json
}
resource "aws_lb" "this" {
...(名前・サブネット・SG などは省略)...
access_logs {
bucket = aws_s3_bucket.logs.id
prefix = "alb"
enabled = true
}
ポリシーが先に出来ていないと作成に失敗しうるので、順番を明示
depends_on = [aws_s3_bucket_policy.logs]
}
terraform apply 後、ALB に何回かアクセスしてからバケットを見ると、ログが出ていました。
aws s3 ls s3://myapp-alb-logs-xxxx/alb/ --recursive | head
※ バケットポリシーの正確な書き方(サービスプリンシパル/リージョンの ELB アカウント等)は、リージョンや時期で変わることがあります。新しく作る場合は公式ドキュメントで現在の推奨を確認してください。アカウントID は data.aws_caller_identity で取れば直書き不要です。
学び
ログを S3 に書くには、Elastic Load Balancing のログ配信サービスに、S3 側で書き込みを許可する(バケットポリシー)。
Terraform が依存を読み取れないときは depends_on で順番を明示。「ポリシー → ALB」の順でないと、作成で失敗することがある。
ログ用 S3 バケットは、ALB と同じリージョンに作る。
暗号化は SSE-S3 を使う。SSE-KMS にするとアクセスログ出力で詰まることがある。
(混同しやすい点)「ALB のアクセスログ」は S3 に出すもの。WAF のログを CloudWatch へ…とは別の話。
おわりに
access_logs を1ブロック足すだけ、に見えて、裏では権限と順番が効いていました😅 ALB のログを初めて S3 に出す人の、先回りの参考になれば嬉しいです🙌