この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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ではエラーになります。
v4でのterraform apply結果
% 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でも参照用途としては使用できます。
v3でserver_side_encryption有効化で作成したバケットを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 Source
data "aws_security_groups" "test" {
tags = {
Name = "notexist"
}
}
v3でのapply結果
% 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" {
│
╵
v4でのapply結果
% 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を使わないようにしてくださいとのことです。