1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Terraform】AWS S3リファクタリング

Last updated at Posted at 2024-10-28

はじめに

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コマンドはコードの変更のみで、モジュールとの整合性は合わせてくれないんですね(?)
勉強不足なのでこのあたりは勉強次第書き直します。

リファクタリング前

main.tf
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
  }
}

リファクタリング後

main.tf
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(ルートモジュール)
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(子モジュール)
./modules/check/variables.tf
variable "name" {
}

variable "account_id" {
}
  • ./modules/check/S3.tf(子モジュール)
./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(子モジュール)
./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(子モジュール)
./modules/check/variables.tf
variable "name" {
}

variable "account_id" {
}
  • ./modules/S3.tf(別ディレクトリ)
./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

  ###### 省略 ######
}

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?