【Terraform】AWS Provider v4.9.0のS3リファクタリングの挙動を試してみた
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。
今回は、タイトルの通りAWS Provider v4.9.0のS3リファクタリングについて挙動を確認してみようと思います。
aws_s3_bucketのリファクタリングについて
先日、v4のリリースで大きな反響があったaws_s3_bucket
のリファクタリングについて変更がありました。
v4.9.0では、aws_s3_bucket
ブロック内にすべて書く方法、aws_s3_bucket_policy
など複数ブロックに分けて書く方法のどちらでも書けるみたいです。
注意点として、両方で記述した場合、ドリフト検出の不具合や競合が生じるみたいです。
今回はその点も検証してみようと思います。
resource/aws_s3_bucket: The acceleration_status, acl, cors_rule, grant, lifecycle_rule, logging, object_lock_configuration.rule, policy, replication_configuration, request_payer, server_side_encryption_configuration, versioning, and website parameters are now Optional. Please refer to the documentation for details on drift detection and potential conflicts when configuring these parameters with the standalone aws_s3_bucket_* resources. (#23985)
v4.9.0
リファクタリングは不要になったわけではない
今回、v4.9.0でaws_s3_bucket
内にプロパティをすべて書き込めるようになりましたが、「リファクタリングが不要になった」と言う意味ではないようです。
aws_s3_bucket
のリファレンスを確認すると、「非推奨の書き方」として取り上げられています。
S3 Bucket Accelerate can be configured in either the standalone resource aws_s3_bucket_accelerate_configuration or with the deprecated parameter acceleration_status in the resource aws_s3_bucket. Configuring with both will cause inconsistencies and may overwrite configuration.
Resource: aws_s3_bucket
今後のマイルストーンでも、2022年4月時点ではとくに言及がありませんでしたが、いつ変更になるかわからないため注意が必要です。
検証してみた
今回は、以下のコードでバージョンアップデート前後の挙動を確認してみようと思います。
適宜バージョンで、コメントアウト部分を変更します。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "4.8.0"
# version = "4.9.0"
}
}
}
data "aws_caller_identity" "example" {}
resource "aws_s3_bucket" "example" {
bucket = "example-${data.aws_caller_identity.example.account_id}"
# S3バケットのデフォルト暗号化
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
# resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
# bucket = aws_s3_bucket.example.bucket
# rule {
# apply_server_side_encryption_by_default {
# sse_algorithm = "AES256"
# }
# }
# }
v4.8.0
terraform plan
を実行すると、v4以降のリファクタリングを行なっていないため怒られました。
takakuni % terraform plan
╷
│ Error: Value for unconfigurable attribute
│
│ with aws_s3_bucket.example,
│ on main.tf line 19, in resource "aws_s3_bucket" "example":
│ 19: resource "aws_s3_bucket" "example" {
│
│ Can't configure a value for "server_side_encryption_configuration": its value will be decided automatically based on the result of applying this configuration.
╵
コードの一部を以下のように変更すると作成できました!
resource "aws_s3_bucket" "example" {
bucket = "example-${data.aws_caller_identity.example.account_id}"
# # S3バケットのデフォルト暗号化
# server_side_encryption_configuration {
# rule {
# apply_server_side_encryption_by_default {
# sse_algorithm = "AES256"
# }
# }
# }
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.example.bucket
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
v4.9.0
ここからが、今回の本題です。
まずは、main.tf
を一部修正して、terraform init -upgrade
を実行します。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
# version = "4.8.0"
version = "4.9.0"
}
}
}
リファクタリング前のコード
terraform plan
を実行すると、無事planが通りますが、Warningが表示されました。
takakuni % terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.example will be created
+ resource "aws_s3_bucket" "example" {
+ acl = "private"
+ bucket = "example-XXXXXXXXXXXX"
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
}
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
│
│ (and one more similar warning elsewhere)
terraform apply
でもリソース作成されましたが、作成後にもWarningが表示される仕様でした。
aws_s3_bucket.example: Creation complete after 2s [id=example-XXXXXXXXXXXX]
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 19, in resource "aws_s3_bucket" "example":
│ 19: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
│
│ (and one more similar warning elsewhere)
╵
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
リファクタリング後のコード
以下のようにコードを変更して、リソースを作成してみました。
resource "aws_s3_bucket" "example" {
bucket = "example-${data.aws_caller_identity.example.account_id}"
# # S3バケットのデフォルト暗号化
# server_side_encryption_configuration {
# rule {
# apply_server_side_encryption_by_default {
# sse_algorithm = "AES256"
# }
# }
# }
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.example.bucket
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
以下、terraform apply
結果の抜粋ですが、Warningも表示されることなくリソースが作成されました。
takakuni % terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.example will be created
+ resource "aws_s3_bucket" "example" {
}
# aws_s3_bucket_server_side_encryption_configuration.example will be created
+ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.example: Creating...
aws_s3_bucket.example: Creation complete after 1s [id=example-XXXXXXXXXXXX]
aws_s3_bucket_server_side_encryption_configuration.example: Creating...
aws_s3_bucket_server_side_encryption_configuration.example: Creation complete after 1s [id=example-XXXXXXXXXXXX]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
競合時のドリフト検出の挙動について
今回のアップデートで、両方のパターンで書ける状態になりました。
しかし、設定値が競合する場合、ドリフト検出がループします。
そのため、競合を避ける必要があります。
どのような挙動になるか、以下のコードで検証してみました。(S3バケット部分以外は抜粋しています。)
暗号化方式の競合が起こるコードになります。
resource "aws_s3_bucket" "example" {
bucket = "example-${data.aws_caller_identity.example.account_id}"
# S3バケットのデフォルト暗号化
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
bucket = aws_s3_bucket.example.bucket
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = "aws/s3"
sse_algorithm = "aws:kms"
}
}
}
初回デプロイ時
初回デプロイ時は、「aws:kms」アルゴリズムでS3バケットは作成されます。
厳密には、「AES256からaws:kmsに上書きする挙動」となります。
% terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_s3_bucket.example will be created
+ resource "aws_s3_bucket" "example" {
+ bucket = "example-XXXXXXXXXXXX"
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
}
}
}
}
# aws_s3_bucket_server_side_encryption_configuration.example will be created
+ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
+ bucket = "example-XXXXXXXXXXXX"
+ rule {
+ apply_server_side_encryption_by_default {
+ kms_master_key_id = "aws/s3"
+ sse_algorithm = "aws:kms"
}
}
}
Plan: 2 to add, 0 to change, 0 to destroy.
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
│
│ (and one more similar warning elsewhere)
╵
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.example: Creating...
aws_s3_bucket.example: Creation complete after 2s [id=example-XXXXXXXXXXXX]
aws_s3_bucket_server_side_encryption_configuration.example: Creating...
aws_s3_bucket_server_side_encryption_configuration.example: Creation complete after 1s [id=example-XXXXXXXXXXXX]
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
╵
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
デプロイ(2回目)
aws_s3_bucketのserver_side_encryption_configuration
プロパティのドリフトが検出されます。
そのため、2回目のterraform apply
時に、「AES256」に更新されます。
% terraform apply
aws_s3_bucket.example: Refreshing state... [id=example-XXXXXXXXXXXX]
aws_s3_bucket_server_side_encryption_configuration.example: Refreshing state... [id=example-XXXXXXXXXXXX]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_s3_bucket.example has changed
~ resource "aws_s3_bucket" "example" {
id = "example-XXXXXXXXXXXX"
+ tags = {}
# (10 unchanged attributes hidden)
~ server_side_encryption_configuration {
~ rule {
# (1 unchanged attribute hidden)
~ apply_server_side_encryption_by_default {
+ kms_master_key_id = "aws/s3"
~ sse_algorithm = "AES256" -> "aws:kms"
}
}
}
# (2 unchanged blocks hidden)
}
# aws_s3_bucket_server_side_encryption_configuration.example has changed
~ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
id = "example-XXXXXXXXXXXX"
# (1 unchanged attribute hidden)
+ rule {
+ bucket_key_enabled = false
+ apply_server_side_encryption_by_default {
+ kms_master_key_id = "aws/s3"
+ sse_algorithm = "aws:kms"
}
}
- rule {
- apply_server_side_encryption_by_default {
- kms_master_key_id = "aws/s3" -> null
- sse_algorithm = "aws:kms" -> null
}
}
}
Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_s3_bucket.example will be updated in-place
~ resource "aws_s3_bucket" "example" {
id = "example-XXXXXXXXXXXX"
tags = {}
# (10 unchanged attributes hidden)
~ server_side_encryption_configuration {
~ rule {
# (1 unchanged attribute hidden)
~ apply_server_side_encryption_by_default {
- kms_master_key_id = "aws/s3" -> null
~ sse_algorithm = "aws:kms" -> "AES256"
}
}
}
# (2 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
│
│ (and one more similar warning elsewhere)
╵
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.example: Modifying... [id=example-XXXXXXXXXXXX]
aws_s3_bucket.example: Modifications complete after 1s [id=example-XXXXXXXXXXXX]
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
╵
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
デプロイ(3回目)
aws_s3_bucket_server_side_encryption_configuration
のrule
プロパティでドリフトが検出されます。
そのため、3回目のterraform apply
時に、再度「"aws:kms"」アルゴリズムに更新されます。
以降は、デプロイ(2回目)とデプロイ(3回目)をループするため、競合を避ける必要があります。
% terraform apply
aws_s3_bucket.example: Refreshing state... [id=example-XXXXXXXXXXXX]
aws_s3_bucket_server_side_encryption_configuration.example: Refreshing state... [id=example-XXXXXXXXXXXX]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_s3_bucket_server_side_encryption_configuration.example has changed
~ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
id = "example-XXXXXXXXXXXX"
# (1 unchanged attribute hidden)
+ rule {
+ bucket_key_enabled = false
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
}
}
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- kms_master_key_id = "aws/s3" -> null
- sse_algorithm = "aws:kms" -> null
}
}
}
Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_s3_bucket_server_side_encryption_configuration.example will be updated in-place
~ resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
id = "example-XXXXXXXXXXXX"
# (1 unchanged attribute hidden)
- rule {
- bucket_key_enabled = false -> null
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256" -> null
}
}
+ rule {
+ apply_server_side_encryption_by_default {
+ kms_master_key_id = "aws/s3"
+ sse_algorithm = "aws:kms"
}
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
╷
│ Warning: Argument is deprecated
│
│ with aws_s3_bucket.example,
│ on main.tf line 13, in resource "aws_s3_bucket" "example":
│ 13: resource "aws_s3_bucket" "example" {
│
│ Use the aws_s3_bucket_server_side_encryption_configuration resource instead
│
│ (and one more similar warning elsewhere)
╵
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket_server_side_encryption_configuration.example: Modifying... [id=example-XXXXXXXXXXXX]
aws_s3_bucket_server_side_encryption_configuration.example: Modifications complete after 0s [id=example-XXXXXXXXXXXX]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
まとめ
今回は、v4.9.0のS3リファクタリング挙動を試してみました。
オプション化で、以前の書き方ができるようになりましたが、引き続きリファクタリングが必要そうです。
この記事が、どなたかの参考になれば幸いです。以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!