Terraform AWS Provider v4へのアップデート
TerraformのAWSProviderv4がリリースされました。
v4へのアップグレードと、アップグレードに伴う破壊的変更に対応したので手順をまとめます。
公式のアップグレードガイドはこちらです。
破壊的変更について
aws_s3_bucket
リソースまわりが大きく変わっています。
aws_s3_bucket
のattributeとして指定していたところ(ライフサイクルルールとかバージョニングとか)が独立したリソースとして扱われるようになりました。
手順
サンプルとして以下のtfファイルを用意してapplyしておきます。
ちなみにaws_s3_bucket
のattributeを指定しないとランダムな名前でS3バケットが作成されます。
provider "aws" {
region = "ap-northeast-1"
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.74.3"
}
}
}
resource "aws_s3_bucket" "normal" {
}
resource "aws_s3_bucket" "server_side_encryption" {
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
resource "aws_s3_bucket" "lifecycle" {
lifecycle_rule {
enabled = true
expiration {
days = "90"
}
}
}
resource "aws_s3_bucket" "acl" {
acl = "private"
}
providerのアップグレード
まずtfファイル内で指定するaws providerのバージョンを4系に変更します。
2022年3月12日時点で最新が4.5.0なので、4.5.0以上の4系で指定しておきます。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
+ version = "~> 4.5.0"
- version = "~> 3.74.3"
}
}
}
修正後、terraform init --upgrade
コマンドを実行します。
% terraform init --upgrade
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.5.0"...
- Installing hashicorp/aws v4.5.0...
- Installed hashicorp/aws v4.5.0 (signed by HashiCorp)
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
試しにterraform plan
この状態でterraform plan
するとv4の記法に則してないので構文エラーになります。
% terraform plan
╷
│ Error: Value for unconfigurable attribute
│
│ with aws_s3_bucket.server_side_encryption,
│ on main.tf line 4, in resource "aws_s3_bucket" "server_side_encryption":
│ 4: resource "aws_s3_bucket" "server_side_encryption" {
│
│ Can't configure a value for "server_side_encryption_configuration": its value will be decided automatically based on the result of applying this configuration.
╵
╷
│ Error: Value for unconfigurable attribute
│
│ with aws_s3_bucket.lifecycle,
│ on main.tf line 14, in resource "aws_s3_bucket" "lifecycle":
│ 14: resource "aws_s3_bucket" "lifecycle" {
│
│ Can't configure a value for "lifecycle_rule": its value will be decided automatically based on the result of applying this configuration.
╵
╷
│ Error: Value for unconfigurable attribute
│
│ with aws_s3_bucket.acl,
│ on main.tf line 24, in resource "aws_s3_bucket" "acl":
│ 24: acl = "private"
│
│ Can't configure a value for "acl": its value will be decided automatically based on the result of applying this configuration.
コードの修正
tfrefactorというツールを使うと既存コードをv4準拠の形に直してくれます。
インストール
wget https://github.com/anGie44/ohmyhcl/releases/download/v0.1.0/tfrefactor_0.1.0_linux_amd64.zip
unzip tfrefactor_0.1.0_linux_amd64.zip
sudo chmod 755 tfrefactor
sudo mv tfrefactor /usr/local/bin
% tfrefactor --help
Usage: tfrefactor [--version] [--help] <command> [<args>]
Available commands are:
resource Refactor resource arguments to individual resources
tfrefactor resource aws_s3_bucket main.tf
するとmain_migrated.tf
というファイルが生成されます。
aws_s3_bucket
内のattributeが消えて、新しいリソースが追加されています。
resource "aws_s3_bucket" "normal" {
}
resource "aws_s3_bucket" "server_side_encryption" {
}
resource "aws_s3_bucket" "lifecycle" {
}
resource "aws_s3_bucket" "acl" {
}
resource "aws_s3_bucket_server_side_encryption_configuration" "server_side_encryption_server_side_encryption_configuration" {
bucket = aws_s3_bucket.server_side_encryption.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_lifecycle_configuration" "lifecycle_lifecycle_configuration" {
bucket = aws_s3_bucket.lifecycle.id
rule {
status = "Enabled"
expiration {
days = "90"
}
}
}
resource "aws_s3_bucket_acl" "acl_acl" {
bucket = aws_s3_bucket.acl.id
acl = "private"
}
再びterraform plan
元のファイル(main.tf)が残ったままだとリソース名が重複してしまいエラーになるのでリネームしてからterraform plan
します。
% mv main.tf main.tf_bk
% terraform plan
╷
│ Error: Missing required argument
│
│ on main_migrated.tf line 27, in resource "aws_s3_bucket_lifecycle_configuration" "lifecycle_lifecycle_configuration":
│ 27: rule {
│
│ The argument "id" is required, but no definition was found.
idが足りずエラーになります。。
idというのはルールの一意な識別子で画面だと以下の赤枠の個所にあたります。
ひとまず一意であればなんでも良いので適当に追加します。
resource "aws_s3_bucket_lifecycle_configuration" "lifecycle_lifecycle_configuration" {
bucket = aws_s3_bucket.lifecycle.id
rule {
+ id = "v4test"
status = "Enabled"
expiration {
days = "90"
}
}
}
三度terraform plan
三度目の正直で通りました。新しく3リソースが作成されます。
% tf plan
aws_s3_bucket.normal: Refreshing state... [id=terraform-20220312121026484500000004]
aws_s3_bucket.acl: Refreshing state... [id=terraform-20220312121026483400000003]
aws_s3_bucket.server_side_encryption: Refreshing state... [id=terraform-20220312121026475200000001]
aws_s3_bucket.lifecycle: Refreshing state... [id=terraform-20220312121026481600000002]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_s3_bucket.acl has changed
~ resource "aws_s3_bucket" "acl" {
id = "terraform-20220312121026483400000003"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
# aws_s3_bucket.lifecycle has changed
~ resource "aws_s3_bucket" "lifecycle" {
id = "terraform-20220312121026481600000002"
~ lifecycle_rule = [
~ {
~ tags = null -> {}
# (8 unchanged elements hidden)
},
]
+ object_lock_enabled = false
+ tags = {}
# (17 unchanged attributes hidden)
}
# aws_s3_bucket.normal has changed
~ resource "aws_s3_bucket" "normal" {
id = "terraform-20220312121026484500000004"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
# aws_s3_bucket.server_side_encryption has changed
~ resource "aws_s3_bucket" "server_side_encryption" {
id = "terraform-20220312121026475200000001"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
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:
+ create
Terraform will perform the following actions:
# aws_s3_bucket_acl.acl_acl will be created
+ resource "aws_s3_bucket_acl" "acl_acl" {
+ acl = "private"
+ bucket = "terraform-20220312121026483400000003"
+ id = (known after apply)
+ access_control_policy {
+ grant {
+ permission = (known after apply)
+ grantee {
+ display_name = (known after apply)
+ email_address = (known after apply)
+ id = (known after apply)
+ type = (known after apply)
+ uri = (known after apply)
}
}
+ owner {
+ display_name = (known after apply)
+ id = (known after apply)
}
}
}
# aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration will be created
+ resource "aws_s3_bucket_lifecycle_configuration" "lifecycle_lifecycle_configuration" {
+ bucket = "terraform-20220312121026481600000002"
+ id = (known after apply)
+ rule {
+ id = "v4test"
+ status = "Enabled"
+ expiration {
+ days = 90
+ expired_object_delete_marker = (known after apply)
}
}
}
# aws_s3_bucket_server_side_encryption_configuration.server_side_encryption_server_side_encryption_configuration will be created
+ resource "aws_s3_bucket_server_side_encryption_configuration" "server_side_encryption_server_side_encryption_configuration" {
+ bucket = "terraform-20220312121026475200000001"
+ id = (known after apply)
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
}
}
}
Plan: 3 to add, 0 to change, 0 to destroy.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
terraform apply
applyも問題なく通りました。これでアップグレード完了です。
% terraform apply
aws_s3_bucket.server_side_encryption: Refreshing state... [id=terraform-20220312121026475200000001]
aws_s3_bucket.normal: Refreshing state... [id=terraform-20220312121026484500000004]
aws_s3_bucket.acl: Refreshing state... [id=terraform-20220312121026483400000003]
aws_s3_bucket.lifecycle: Refreshing state... [id=terraform-20220312121026481600000002]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_s3_bucket.acl has changed
~ resource "aws_s3_bucket" "acl" {
id = "terraform-20220312121026483400000003"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
# aws_s3_bucket.lifecycle has changed
~ resource "aws_s3_bucket" "lifecycle" {
id = "terraform-20220312121026481600000002"
~ lifecycle_rule = [
~ {
~ tags = null -> {}
# (8 unchanged elements hidden)
},
]
+ object_lock_enabled = false
+ tags = {}
# (17 unchanged attributes hidden)
}
# aws_s3_bucket.normal has changed
~ resource "aws_s3_bucket" "normal" {
id = "terraform-20220312121026484500000004"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
# aws_s3_bucket.server_side_encryption has changed
~ resource "aws_s3_bucket" "server_side_encryption" {
id = "terraform-20220312121026475200000001"
+ object_lock_enabled = false
+ tags = {}
# (18 unchanged attributes hidden)
}
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:
+ create
Terraform will perform the following actions:
# aws_s3_bucket_acl.acl_acl will be created
+ resource "aws_s3_bucket_acl" "acl_acl" {
+ acl = "private"
+ bucket = "terraform-20220312121026483400000003"
+ id = (known after apply)
+ access_control_policy {
+ grant {
+ permission = (known after apply)
+ grantee {
+ display_name = (known after apply)
+ email_address = (known after apply)
+ id = (known after apply)
+ type = (known after apply)
+ uri = (known after apply)
}
}
+ owner {
+ display_name = (known after apply)
+ id = (known after apply)
}
}
}
# aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration will be created
+ resource "aws_s3_bucket_lifecycle_configuration" "lifecycle_lifecycle_configuration" {
+ bucket = "terraform-20220312121026481600000002"
+ id = (known after apply)
+ rule {
+ id = "v4test"
+ status = "Enabled"
+ expiration {
+ days = 90
+ expired_object_delete_marker = (known after apply)
}
}
}
# aws_s3_bucket_server_side_encryption_configuration.server_side_encryption_server_side_encryption_configuration will be created
+ resource "aws_s3_bucket_server_side_encryption_configuration" "server_side_encryption_server_side_encryption_configuration" {
+ bucket = "terraform-20220312121026475200000001"
+ id = (known after apply)
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
}
}
}
Plan: 3 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_server_side_encryption_configuration.server_side_encryption_server_side_encryption_configuration: Creating...
aws_s3_bucket_acl.acl_acl: Creating...
aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration: Creating...
aws_s3_bucket_acl.acl_acl: Creation complete after 0s [id=terraform-20220312121026483400000003,private]
aws_s3_bucket_server_side_encryption_configuration.server_side_encryption_server_side_encryption_configuration: Creation complete after 0s [id=terraform-20220312121026475200000001]
aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration: Still creating... [10s elapsed]
aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration: Still creating... [20s elapsed]
aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration: Still creating... [30s elapsed]
aws_s3_bucket_lifecycle_configuration.lifecycle_lifecycle_configuration: Creation complete after 31s [id=terraform-20220312121026481600000002]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
ライフサイクルルール名(id)も変わってました。
Discussion