はじめに
Qiitaの上手な書き方がわからないpiromoです。TerraformもAWSもS3も「???」ですが、仕事でS3のリファクタリングをするというタスクがあったので、以下備忘録です。今回のタスクで0.000001mmだけTerraformが分かった気がします。嘘です。
概要
Terraform のAWSプロバイダーのバージョンをすでにv4以上に引き上げている環境で、以下のようなエラーが出力されていました。しばらくそのままにしていましたが、将来的にS3のリファクタリングは必須なので、今回泣きながらリファクタリングを進めました。
╷
│ Error: Argument is deprecated
│
│ with aws_s3_bucket.this,
│ on main.tf line 50, in resource "aws_s3_bucket" "log":
│ 19: resource "aws_s3_bucket" "log" {
│
│ Use the aws_s3_bucket_lifecycle_configuration resource instead
╵
背景
・Terraform AWS プロバイダーのバージョン 4.0以降、aws_s3_bucket
リソースが過負荷となりユーザが単一の構成で管理することが難しくなってきました。その負荷を軽減させるために、新しいS3バケット管理リソースを導入したそうです。
・リファクタリングを行わない場合は、terraform plan
時に予期しないエラーや警告が出力される可能性があります。
・状態の不一致やデータ損失なしで新しいリソースタイプに移行するには、terraform import
ステートメントを使用して状態の新しいタイプを追跡する必要があります。
importブロックを使用したS3リファクタリング
S3リソースをリファクタリングする際に、リソースが再作成されてしまいます。そのため公式の通りimportブロックを利用することで、リソースの再作成が行わられずにコードの修正のみを実施できました。
実施手順
①S3のリファクタリングとimportブロックの記載、反映
②importブロックのみを削除して再度反映
import
ブロック使用時の注意
import
ブロックは、ルートモジュールに記載する必要があります。
※ルートモジュールとは、Terraform CLIを実行する作業ディレクトリのことを指します。
-refresh-only
コマンド
import
ブロックと似たような動作をするものとして-refresh-only
コマンドの利用も試しましたが、-refresh-only
コマンドでの反映後に再度通常の反映をするとresouceの再作成が行われてしまいました。
-refresh-only
コマンドはコードの変更のみで、モジュールとの整合性は合わせてくれないんですね(?)
勉強不足なのでこのあたりは勉強次第書き直します。
リファクタリング前
resource "aws_s3_bucket" "log" {
bucket = "Terraform-Test-log"
policy = data.aws_iam_policy_document.s3.json
lifecycle_rule {
enabled = true
transition {
days = 0
storage_class = "INTELLIGENT_TIERING"
}
}
versioning {
enabled = true
}
}
リファクタリング後
resources "aws_s3_bucket" "log" {
bucket = "Terraform-Test-log"
}
resource "aws_s3_bucket_policy" "log" {
bucket = aws_s3_bucket.log.id
policy = data.aws_iam_policy_document.s3.json
}
resource "aws_s3_bucket_lifecycle_configuration" "log" {
bucket = aws_s3_bucket.log.id
rule {
id = "rule1" #一意のrule_id(ルール名)を入れる必要あり
status = "Enabled"
transition {
days = 0
storage_class = "INTELLIGENT_TIERING"
}
}
}
resource "aws_s3_bucket_versioning" "log" {
bucket = aws_s3_bucket.log.id
versioning_configuration {
status = "Enabled"
}
}
import {
id = "Terraform-Test-log" #リファクタリング対象のバケット名を記載
to = aws_s3_bucket.log #リファクタリング対象のresourceを記載
}
import {
id = "Terraform-Test-log" #リファクタリング対象のバケット名を記載
to = aws_s3_bucket_policy.log #リファクタリング対象のresourceを記載
}
import {
id = "Terraform-Test-log" #リファクタリング対象のバケット名を記載
to = aws_s3_bucket_lifecycle_configuration.log #リファクタリング対象のresourceを記載
}
import {
id = "Terraform-Test-log" #リファクタリング対象のバケット名を記載
to = aws_s3_bucket_versioning.log #リファクタリング対象のresourceを記載
}
この後、import
ブロックのみを削除して再度反映します。
importブロックを使用した複数のS3リファクタリング
概要
今回はresourceで管理されている複数のS3をリファクタリングする必要がありました。
さらにS3モジュールはルートモジュールに、reourcesは別ディレクトリのファイルにあり、記載方法を変える必要がありました。
リファクタリング前
-
main.tf
(ルートモジュール)
module "paromo"
source = "./modules/check"
name = "paromo"
account_id = 123456789876
module "piromo"
source = "./modules/check"
name = "piromo"
account_id = 223456789876
-
./modules/check/variables.tf
(子モジュール)
variable "name" {
}
variable "account_id" {
}
-
./modules/check/S3.tf
(子モジュール)
locals {
bucket_name = "Terraform-Test-log"-${var.name}
}
###### 省略 ######
resource "aws_s3_bucket" "log" {
bucket = local.bucket_name
policy = data.aws_iam_policy_document.s3.json
lifecycle_rule {
enabled = true
transition {
days = 0
storage_class = "INTELLIGENT_TIERING"
}
}
versioning {
enabled = true
}
}
リファクタリング後
-
./modules/check/S3.tf
(子モジュール)
module "paromo"
source = "./modules/check"
name = "paromo"
account_id = 123456789876
module "piromo"
source = "./modules/check"
name = "piromo"
account_id = 223456789876
############################## ここから ##############################
import {
id = "paromo" #リファクタリング対象のバケット名を記載
to = module.paromo.aws_s3_bucket.log #リファクタリング対象のresourceを記載
}
import {
id = "paromo" #リファクタリング対象のバケット名を記載
to = module.paromo.aws_s3_bucket_policy.log #リファクタリング対象のresourceを記載
}
import {
id = "paromo" #リファクタリング対象のバケット名を記載
to = module.paromo.aws_s3_bucket_lifecycle_configuration.log #リファクタリング対象のresourceを記載
}
import {
id = "paromo" #リファクタリング対象のバケット名を記載
to = module.paromo.aws_s3_bucket_versioning.log #リファクタリング対象のresourceを記載
}
import {
id = "piromo" #リファクタリング対象のバケット名を記載
to = module.piromo.aws_s3_bucket.log #リファクタリング対象のresourceを記載
}
import {
id = "piromo" #リファクタリング対象のバケット名を記載
to = module.piromo.aws_s3_bucket_policy.log #リファクタリング対象のresourceを記載
}
import {
id = "piromo" #リファクタリング対象のバケット名を記載
to = module.piromo.aws_s3_bucket_lifecycle_configuration.log #リファクタリング対象のresourceを記載
}
import {
id = "piromo" #リファクタリング対象のバケット名を記載
to = module.piromo.aws_s3_bucket_versioning.log #リファクタリング対象のresourceを記載
}
############################## ここまで ##############################
import
ブロック内のid
を工夫することで、脳死で作業できるようにしたかったのですが、以下のような形はできなかったので直接S3バケット名を記載しました。
import {
id = module.paromo.name
to = module.paromo.aws_s3_bucket.log
}
-
./modules/check/variables.tf
(子モジュール)
variable "name" {
}
variable "account_id" {
}
-
./modules/S3.tf
(別ディレクトリ)
locals {
bucket_name = "Terraform-Test-log"-${var.name}
}
###### 省略 ######
############################## ここから ##############################
resources "aws_s3_bucket" "log" {
bucket = local.id
}
resource "aws_s3_bucket_policy" "log" {
bucket = aws_s3_bucket.log.id
policy = data.aws_iam_policy_document.s3.json
}
resource "aws_s3_bucket_lifecycle_configuration" "log" {
bucket = aws_s3_bucket.log.id
rule {
id = "rule1" #一意のrule_id(ルール名)を入れる必要あり
status = "Enabled"
transition {
days = 0
storage_class = "INTELLIGENT_TIERING"
}
}
}
resource "aws_s3_bucket_versioning" "log" {
bucket = aws_s3_bucket.log.id
versioning_configuration {
status = "Enabled"
}
}
############################## ここまで ##############################
S3リファクタリングその他
aws_s3_bucket_acl
acl = "private"
を挿入する場合、aws_s3_bucket_ownership_controls
を設定する必要があります。
なおリファクタリングの際にaws_s3_bucket_acl
を削除すると、aws_s3_bucket_ownership_controls
は変更されずデフォルトの設定のままになります。以下の通り、2023年にデフォルトのACL有効/無効が変更されたので、一つのモジュールを複数のアカウントで使用している場合は、ACLの設定を見直しましょう。
2023年4月からAmazon S3 で、すべての新しいバケットに対して自動的に S3 パブリックアクセスブロックが有効化、アクセスコントロールリストが無効化されました。
参考リンク:AWS-NEWS
resource "aws_s3_bucket" "example" {
bucket = "my-tf-example-bucket"
}
resource "aws_s3_bucket_ownership_controls" "example" {
bucket = aws_s3_bucket.example.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
resource "aws_s3_bucket_acl" "example" {
depends_on = [aws_s3_bucket_ownership_controls.example]
bucket = aws_s3_bucket.example.id
acl = "private"
}
acl = "private"
以外のパターンについては、以下のドキュメントを参考にしてください。
参考リンク:Resource: aws_s3_bucket_acl
aws_s3_bucket_replication_configuration
# Must have bucket versioning enabled first
となっているので、リファクタリングの際はdepends_on = [aws_s3_bucket_versioning.source]
を挿入する必要があります。
参考リンク:aws_s3_bucket_replication_configuration
resource "aws_s3_bucket_replication_configuration" "replication" {
provider = aws.central
# Must have bucket versioning enabled first
depends_on = [aws_s3_bucket_versioning.source]
role = aws_iam_role.replication.arn
bucket = aws_s3_bucket.source.id
###### 省略 ######
}
参考