Terraform AWS Provider Version 4がリリースされました
2022/2/11に Terraform AWS Provider Version 4がリリースされました。2/22現在、もうVersion 4.2まででています。実際に触ってみて何が変わったのか確認したいと思います。
aws_s3_bucketの大規模リファクタリング
要は「aws_s3_bucket
がデカくなりすぎて大変だから、細かく分けようぜ!」ということです。
御存知の通りS3は非常に多機能です。そしてTerraformではその機能の殆どをaws_s3_bucket
のattributeで設定していました。
以下はaws_s3_bucket
のコード例です。
resource "aws_s3_bucket" "v3" { bucket = local.bucket_name acceleration_status = "Enabled" acl = "private" cors_rule { allowed_headers = ["*"] allowed_methods = ["PUT", "POST"] allowed_origins = ["https://s3-website-test.hashicorp.com"] expose_headers = ["ETag"] max_age_seconds = 3000 } # `acl`とコンフリクトするためコメントアウト # grant { # type = "Group" # permissions = ["READ_ACP", "WRITE"] # uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" # } lifecycle_rule { id = "log" enabled = true prefix = "log/" tags = { rule = "log" autoclean = "true" } transition { days = 30 storage_class = "STANDARD_IA" } transition { days = 60 storage_class = "GLACIER" } expiration { days = 90 } } logging { target_bucket = aws_s3_bucket.log_bucket.id target_prefix = "log/" } # `replication_configuration`とコンフリクトするためコメントアウト # object_lock_configuration { # object_lock_enabled = "Enabled" # # rule { # default_retention { # mode = "COMPLIANCE" # days = 3 # } # } # } policy = <<-EOF { "Id": "Policy1446577137248", "Statement": [ { "Action": "s3:PutObject", "Effect": "Allow", "Principal": { "AWS": "${data.aws_elb_service_account.current.arn}" }, "Resource": "arn:${data.aws_partition.current.partition}:s3:::${local.bucket_name}/*", "Sid": "Stmt1446575236270" } ], "Version": "2012-10-17" } EOF replication_configuration { role = aws_iam_role.replication.arn rules { id = "foobar" status = "Enabled" filter { tags = {} } destination { bucket = aws_s3_bucket.destination.arn storage_class = "STANDARD" replication_time { status = "Enabled" minutes = 15 } metrics { status = "Enabled" minutes = 15 } } } } request_payer = "Requester" server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { kms_master_key_id = aws_kms_key.mykey.arn sse_algorithm = "aws:kms" } } } versioning { enabled = true } website { index_document = "index.html" error_document = "error.html" } }
まあ実際こんなヘンテコな設定することは無いと思いますが、上記で書いたattributeのうち、一番上のbucket
以外は今回リリースされたv4ではエラーになります。
% terraform apply ╷ │ Error: Value for unconfigurable attribute │ │ with aws_s3_bucket.v3, │ on s3.tf line 5, in resource "aws_s3_bucket" "v3": │ 5: resource "aws_s3_bucket" "v3" { │ │ Can't configure a value for "server_side_encryption_configuration": its value will be decided │ automatically based on the result of applying this configuration. ╵ (以下略)
こんな感じのCan't configure a value for 〜
というエラーが各attributeにて発生します。
v4では各Attribute毎にresourceが用意されているので、こちらを使います。
resource "aws_s3_bucket" "v4" { bucket = local.bucket_name - server_side_encryption_configuration { - rule { - apply_server_side_encryption_by_default { - kms_master_key_id = aws_kms_key.mykey.arn - sse_algorithm = "aws:kms" - } - } - } } + resource "aws_s3_bucket_server_side_encryption_configuration" "v4" { + bucket = aws_s3_bucket.v4.id + + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = aws_kms_key.mykey.arn + sse_algorithm = "aws:kms" + } + } + }
前述のエラーメッセージにも記述がありますが、今回エラーになるようになったaws_s3_bucket
の各Attributeはリソース作成後、v4でも参照用途としては使用できます。
% terraform state show aws_s3_bucket.v3 # aws_s3_bucket.v3: resource "aws_s3_bucket" "v3" { (略) server_side_encryption_configuration = [ { rule = [ { apply_server_side_encryption_by_default = [ { kms_master_key_id = "arn:aws:kms:ap-northeast-1:012345678901:key/beadbbd7-7add-4608-9cbc-f9dd91c34ecc" sse_algorithm = "aws:kms" }, ] bucket_key_enabled = false }, ] }, ] (略) }
ですのでv3からv4にアップグレードする際は、アップグレード後に新しいリソースを書いて、importを行なってください。
% terraform import aws_s3_bucket_server_side_encryption_configuration.sample test20220220 aws_s3_bucket_server_side_encryption_configuration.sample: Importing from ID "test20220220"... aws_s3_bucket_server_side_encryption_configuration.sample: Import prepared! Prepared aws_s3_bucket_server_side_encryption_configuration for import aws_s3_bucket_server_side_encryption_configuration.sample: Refreshing state... [id=test20220220] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
デフォルトリソースの作成削除が可能に
これまで参照と更新しかできなかったデフォルトリソース(aws_default_vpc
,aws_default_subnet
) に対して作成と削除もできるようになりました、だそうですがデフォルトリソースをTerraformで扱ったことがなかったのでピンときませんでした。実際にaws_default_vpc
を触ってみました。
v3
v3では、デフォルトのVPCが存在している場合、(各リージョンに1つしか作成できないので)新たにデフォルトVPCを作成することはせず、
tags
enable_dns_support
enable_dns_hostnames
enable_classiclink
の更新のみ可能です。
resource "aws_default_vpc" "default" { tags = { Name = "hoge hoge" } }
そして、aws_default_vpc
リソースのコードを削除してapplyすると、
- resource "aws_default_vpc" "default" { - tags = { - Name = "hoge hoge" - } - }
TerraformのStateからはaws_default_vpc
は削除されますが、実際のリソースはそのまま残り続けます。(設定したタグも残ります)
また、デフォルトVPCが存在していない場合にこのリソースを使うとError: No default VPC found in this region.
というエラーになります。
v4
v4でも一部設定を更新できる、destoryしてもstateから消えるだけでリソース削除はされないは同じです。
違うのは2つ。まずデフォルトVPCが存在していない場合にこのリソースを使ってapplyすると、新たにデフォルトVPCを作成します。作成時にサブネットなどの紐づくリソースも併せて作成されます。
もう一つは、新たにforce_destroy
attributeが追加されています。これをtrue
にすると…
resource "aws_default_vpc" "default" { force_destroy = true }
この状態でapplyしても特に何も変わりません。が、このコードを削除した時、
- resource "aws_default_vpc" "default" { - force_destroy = true - }
stateから消えるだけでなくリソースも削除されるようになります。なお、事前にデフォルトVPCに紐づくサブネット、インターネットゲートウェイ、デフォルト以外のセキュリティグループなどのリソースを削除しておく必要があります。
Provider設定の改良
Providerブロックのargumentsが色々増えています。ざっと眺めて見ましたが、普段使いそうなのはありませんでした。特殊な要件がある場合に役立つかもしれません。以下に新argumentsの一覧があるのでご確認ください。
複数値を返すData Sourceで値がゼロになってもエラーにならないように
aws_security_groups
のような、同種リソースを複数個配列型にして持つData Sourceがあります。v3では1つもリソースを取得できなかった場合はエラーを返します。v4ではエラーにならなくなりました。
data "aws_security_groups" "test" { tags = { Name = "notexist" } }
% terraform apply ╷ │ Error: Your query returned no results. Please change your search criteria and try again. │ │ with data.aws_security_groups.test, │ on plural.tf line 1, in data "aws_security_groups" "test": │ 1: data "aws_security_groups" "test" { │ ╵
% terraform apply No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. Apply complete! Resources: 0 added, 0 changed, 0 destroyed. % terraform state list data.aws_security_groups.test % terraform state show data.aws_security_groups.test # data.aws_security_groups.test: data "aws_security_groups" "test" { arns = [] id = "ap-northeast-1" ids = [] tags = { "Name" = "notexist" } vpc_ids = [] }
これを利用して、該当セキュリティグループがあるときだけリソースを作成する、なければしない(あるいはその逆)みたいなことができますね。
resource "aws_alb" "test" { count = (length(data.aws_security_groups.test.ids) > 0) ? 1 : 0 name = "test" internal = false load_balancer_type = "application" subnets = [for subnet in aws_default_subnet.default: subnet.id] security_groups = data.aws_security_groups.test.ids }
認証方法の変更
AWS Providerの認証方法は大きく分けて3つあります。そして上から順に優先して使われます。
provider
ブロック内で指定するprofile
とかassume_role
といったarugumentを使う方法です。
- 環境変数
AWS_ACCESS_KEY_ID
とかAWS_SECRET_ACCESS_KEY
とかAWS_PROFILE
とかですね。
- クレデンシャル/コンフィグファイル
~/.aws/credentials
や/.aws/config
に書かれている内容を使います。
v3では上記1から設定されているか調べて、その値が無効な場合、次の2の設定を調べます。2も無効な場合は3を調べます。というように「無効だったら次の優先度の設定を調べる」という挙動になっています。
v4では1から設定されているか調べて、「設定されているけど無効だったら即エラーを返す」という挙動に変更になりました。SDKやCLIと挙動を揃える意図だそうです。
空文字指定の非推奨
リソースのattribute値に空文字""
を入れるとそのattributeは未指定と解釈されデフォルト値が入るという挙動をするリソースが色々あります。v4からは多くのリソースで空文字を指定するとエラーになるようになりました。代わりにnull
を指定するか、そもそもそのattributeを使わないようにしてくださいとのことです。