🕑

Terraform で AWS S3 public access block に対応する

2023/05/16に公開
lib version
Terraform 1.4.6
hashicorp/aws 4.67.0

2023/04 より AWS S3 のパブリックアクセスブロックが自動で有効になったんだけども、その影響で Terraform で設定するときにもひと手間増えたので備忘録としてメモ。

まずは今まで通りにやってみる

だいぶ端折ってるけども、今回に影響がある部分だけを抜粋したのがコレ。

main.tf
provider "aws" {}

#  S3 バケットを作成
# see: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket
resource "aws_s3_bucket" "main" {
  bucket = "fixed-public-access-block"
}

# バケットポリシーの内容を定義
# see: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document
data "aws_iam_policy_document" "main" {
  statement {
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }
    actions = [
      "s3:GetObject",
    ]
    resources = [
      aws_s3_bucket.main.arn,
      "${aws_s3_bucket.main.arn}/*",
    ]
  }
}

# バケットポリシーをバケットに紐づける
# see: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy
resource "aws_s3_bucket_policy" "main" {
  bucket = aws_s3_bucket.main.id
  policy = data.aws_iam_policy_document.main.json
}

これを apply してみる。

$ terraform apply
 
 (snip)
 
aws_s3_bucket.main: Creating...
aws_s3_bucket.main: Creation complete after 2s [id=fixed-public-access-block]
data.aws_iam_policy_document.main: Reading...
data.aws_iam_policy_document.main: Read complete after 0s [id=1693531708]
aws_s3_bucket_policy.main: Creating...
╷
│ Error: Error putting S3 policy: AccessDenied: Access Denied
│       status code: 403, request id: XD8AXG19HB5W36PR, host id: yOszjy8Dl7jr+snu1TkZ4JHhVZSypsyYwYkl6YO3rI8oHKUqCeDWZZptqyb5Z86sMgYu/QVGgQcizL0N+Ab28w==
│
│   with aws_s3_bucket_policy.main,
│   on main.tf line 30, in resource "aws_s3_bucket_policy" "main":30: resource "aws_s3_bucket_policy" "main" {
│
╵

すると、以前までは問題なかったトコロで Access Denied なエラーが返ってくる。
これが今回の S3 に入った変更の影響で、バケットやオブジェクトへのパブリックアクセスを含むポリシーを設定しようとしてるので拒否られてしまっている。

パブリックアクセスブロックを設定してみる

ホントは厳密に設定するのが良いんだけども、今回は一旦まるっと off にした設定を追加。

main.tf
(snip)

# see: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block
resource "aws_s3_bucket_public_access_block" "main" {
  bucket                  = aws_s3_bucket.main.id
  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

これで apply してみる。

$ terraform apply

(snip)

aws_s3_bucket_public_access_block.main: Creating...
aws_s3_bucket_policy.main: Creating...
aws_s3_bucket_public_access_block.main: Creation complete after 1s [id=fixed-public-access-block]
╷
│ Error: Error putting S3 policy: AccessDenied: Access Denied
│       status code: 403, request id: SQKDG5269Q8Q3QHE, host id: dJAxDB2SXP2EsD3uQv7WKQead6zzv8XCuk4js6fzBU4CwenSihu+ykbxzcy/XA8p1j5GDk5kWlA=
│
│   with aws_s3_bucket_policy.main,
│   on main.tf line 30, in resource "aws_s3_bucket_policy" "main":30: resource "aws_s3_bucket_policy" "main" {
│
╵

あれ?なぜかまた拒否られた。
上のログを見るに aws_s3_bucket_public_access_block の設定は上手くいってるっぽいし、コンソールで確認してみたらちゃんと反映されていたので、どうやらパブリックアクセスブロックの設定する前にポリシー設定しようとしてしまってるっぽい。

試しに何も設定を変えずにもう一度 apply してみる。

$ terraform apply

(snip)

aws_s3_bucket_policy.main: Creating...
aws_s3_bucket_policy.main: Creation complete after 1s [id=fixed-public-access-block]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

上手く通った。ってことはリソースを実行する順番ミスってるのね。

リソースの実行順序を指定する

一旦今までの作業をなかったことにするために destroy する。

$ terraform destroy

(snip)

aws_s3_bucket_public_access_block.main: Destroying... [id=fixed-public-access-block]
aws_s3_bucket_policy.main: Destroying... [id=fixed-public-access-block]
aws_s3_bucket_policy.main: Destruction complete after 1s
aws_s3_bucket_public_access_block.main: Destruction complete after 1s
aws_s3_bucket.main: Destroying... [id=fixed-public-access-block]
aws_s3_bucket.main: Destruction complete after 1s

Destroy complete! Resources: 3 destroyed.

次に depends_on を使って aws_s3_bucket_policy の実行を aws_s3_bucket_public_access_block の後になるように指定する。

main.tf
@@ -30,6 +30,10 @@ data "aws_iam_policy_document" "main" {
 resource "aws_s3_bucket_policy" "main" {
   bucket = aws_s3_bucket.main.id
   policy = data.aws_iam_policy_document.main.json
+
+  depends_on = [
+    aws_s3_bucket_public_access_block.main,
+  ]
 }

これを apply してみる。

$ terraform apply

(snip)

aws_s3_bucket.main: Creating...
aws_s3_bucket.main: Creation complete after 2s [id=fixed-public-access-block]
data.aws_iam_policy_document.main: Reading...
aws_s3_bucket_public_access_block.main: Creating...
data.aws_iam_policy_document.main: Read complete after 0s [id=1693531708]
aws_s3_bucket_public_access_block.main: Creation complete after 1s [id=fixed-public-access-block]
aws_s3_bucket_policy.main: Creating...
aws_s3_bucket_policy.main: Creation complete after 0s [id=fixed-public-access-block]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

全部うまく通ったし、ログを見てもちゃんと aws_s3_bucket_public_access_block が完了するのを待ってから aws_s3_bucket_policy が実行されてる。めでたしめでたし。

おわりに

aws_s3_bucket_public_access_block まで一通り設定を書いた状態から depends_on を消した状態で実行してみたら、それはエラーにならずにちゃんと通った。リソースそれぞれの実行時間の影響なのかなんなのか?
それでも「書いて実行したらおしまい」とはいかず、メンテしていかないといけないのが Terraform なので、 depends_on などで制御できる部分はめんどくさがらずに明記しておくのが良いと思う。

Discussion