1. ホーム
  2. 記事一覧
  3. Terraform AWS S3リモートバックエンドを用いてtfstateを管理してみよう

2024.03.29

Terraform AWS S3リモートバックエンドを用いてtfstateを管理してみよう

    こちらの記事では、Terraformに必要不可欠なtfstateファイルを、AWSストレージサービスのAmazon S3を使用して管理する方法を解説します。

    tfstateファイルの管理方法は複数存在しますが、今回はS3で管理することに焦点を絞ります。

    S3リモートバックエンドを使う理由

    Amazon S3はイレブンナイン(99.999999999%)の耐久性、99.99%の可用性を実現しています。よほどのことがない限りtfstateファイルを消失してしまうことは考えにくいでしょう。

    https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/DataDurability.html

    チーム開発において、複数の開発者が同じインフラストラクチャを管理する場合、Stateファイルの差分が発生する可能性があります。リモートバックエンドを使用することでなくすことができます。

    これらのことから、リモートバックエンドは実際の開発現場でも使われています。記事を通して理解を深めましょう。

    Terraformとは

    Terraformとは、インフラ環境をコードで定義して構築するIaC(Infrastructure as Code)ツールの一つです。アメリカのソフトウェア企業である、HashiCorp社が開発したオープンソースツールです。HCL(HashiCorp Configuration Language)と呼ばれる独自の言語を使用し、JSONやYAMLと同じような形式で記述をすることができます。

    特徴の一つとして、読みやすく保守しやすいことが挙げられます。

    また、Terraformでは主に、準備、計画、実行、削除の4つを管理するだけというシンプルさを持っており、最低限この4つのコマンドさえ覚えていればTerraformを扱えるというのも特徴の一つです。

    IaCについては以下のリンクで解説しています。

    https://envader.plus/article/136

    リモートバックエンドとは

    リモートバックエンドとは、tfstateファイルの管理をローカル環境以外の場所で管理する方法を意味します。

    Amazon S3、Azure Blob Storage、Google Cloud Storage、Terraform Cloudなどをリモートバックエンドとして利用できます。

    このリモートバックエンドを利用することで、安全にtfstateファイルを管理することが可能になります。

    https://developer.hashicorp.com/terraform/language/settings/backends/configuration

    tfstateファイルとは

    tfstateファイルとは、Terraformを使用してどのようなリソースを構築したかが記録されているファイルで、JSON形式で記述されています。

    Terraformは、あるべき姿を記述したtfファイルと、リソースの現状を記録したtfstateファイルの情報をもとに二つのファイルの差分を計算します。

    新しくリソースを作成、更新、または削除する際は、この計算をもとに判断します。

    tfstateファイルに関してはこちらで解説しています。

    https://envader.plus/article/199

    リモートバックエンドを利用するメリット

    ここからは、リモートバックエンドを利用するメリットについて考えます。

    運用、セキュリティ、耐久性の観点を用いて整理します。

    運用

    リモートバックエンドを利用することで、plan実行時にはtfstateファイルをリモートから自動的に読み込んでくれ、apply時であれば、自動的に保存してくれます。このメリットは非常に大きいです。

    仮にGitHubなどのバージョン管理システムでtfstateファイルを管理していた場合、手動でpull、pushをしなければなりません。仮にpull、pushを忘れた場合、他のメンバーが加えた変更、自分が加えた変更をチームで共有できないことになり、開発で手戻りや重複が発生してしまいます。

    リモートバックエンドを利用すれば、自動的にpull、push作業を実行してくれることになるため、人起因のミスをなくすことができます。

    セキュリティ

    Amazon S3などのストレージサービスを利用することで、ファイル送受信時の暗号化、保存したファイルの暗号化などのサポートを受けることができます。IAM Policyを設定することでファイルにアクセスできる対象を絞ることもできます。

    tfstateファイルは、DBのユーザー名、パスワードなど機密情報もすべてプレーンテキストで保存されるため、仮にプロジェクトに関わりのない人がtfstateファイルの中身を見てしまった場合、パスワードの流出などに発展しかねません。

    リモートバックエンドを利用することで、このようなリスクを排除することが可能です。

    耐久性

    冒頭にも記述しましたが、Amazon S3はイレブンナインの耐久性、99.99%の可用性を持つよう設計されていますので、tfstateファイルが消失してしまう可能性は低いでしょう。

    また、バージョニングを利用することで、万が一誤ってファイルを削除してしまってもファイルを復元することも可能です。

    ローカルにtfstateファイルを保存していた場合、PC破損でのファイル消失、誤操作によるファイル削除などで構築していた環境の情報を失ってしまうリスクが考えられます。

    tfstateをローカルで管理するデメリット

    Terraformでは、terraform apply実行するとローカル環境にtfstateファイルが作成されます。

    複数人でのチーム開発を行う場合、それぞれのローカル環境でtfstateファイルを管理することになります。この状態では、それぞれの環境でtfstateファイルに差分が生まれてしまい、チーム開発をすることが非常に困難になります。

    チーム開発ではなく、自身の勉強目的、個人開発のみであれば、この方法で管理しても問題ありません。

    Terraformの環境構築

    AWSを使ってTerraformを実行するには、以下の環境構築作業が必要になります。

    • AWS CLI(AWS Command Line Interface)のインストール
    • AWS CLIに関連するプロファイルの設定
    • Terraformのインストール

    また、terraform planterraform applyなどの基本的なコマンドの意味を理解することも欠かせません。

    以下の記事では、環境構築から基本的なコマンドの意味まで網羅的に解説しています。環境構築が済んでいない方は次のリンクよりご覧ください。

    https://envader.plus/article/162

    S3でリモートバックエンドを実装する

    ここからは実際にリソースを作成し、tfstateファイルをリモートバックエンドで管理できるようにしていきます。

    S3バケットの作成

    初めに、リモートバックエンドでtfstateファイルを管理するためのS3バケットを作成します。

    S3バケットを作成する際、バケットの名前は全AWSユーザーの間でグローバルに一意である必要があります。すでに同名のバケットが存在する場合、エラーが発生しバケットが作成できないため注意が必要です。

    また、S3で扱える引数にはいくつか非推奨のものがあるため、詳細は以下をご覧ください。

    https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket

    main.tfファイルを作成し、以下の内容を記述します。

    # main.tf
    # S3bucket
    resource "aws_s3_bucket" "remote_backend" {
      bucket = "remote-backend-s3-1234" # 一意の名前である必要がある
      lifecycle {
        prevent_destroy = true
      }
    
      tags = {
        Name        = "remote-backend-s3"
        Environment = "dev"
      }
    }
    
    # バージョニングの設定
    resource "aws_s3_bucket_versioning" "remote_backend" {
      bucket = aws_s3_bucket.remote_backend.id
      versioning_configuration {
        status = "Enabled"
      }
    }

    lifecycleでは、terraform destroyコマンドを実行したときにバケットが削除されないように設定しています。Terraformを使ってバケットを削除したい場合は、この値をfalseへ変更する必要があります。

    S3リソースを定義したら、Terraformのバージョンやプロバイダを設定します。

    今回はversions.tfファイルを作成して内容を記述します。

    # versions.tf
    terraform {
      required_version = ">= 1.0.0"
    
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.3.0"
        }
      }
    }
    
    provider "aws" {
      region = "ap-northeast-1"
    }

    次にterraform initコマンドを実行し、プロジェクトを初期化します。

    terraform init
    
    Initializing the backend...
    
    Initializing provider plugins...
    - Finding hashicorp/aws versions matching "5.3.0"...
    - Installing hashicorp/aws v5.3.0...
    - Installed hashicorp/aws v5.3.0 (signed by HashiCorp)
    
    ...
    ...
    Terraform has been successfully initialized!

    初期化が完了したら、terraform planを実行して内容を確認後、terraform applyでS3バケットを作成します。

    terraform plan
    
    terraform apply

    リモートバックエンドの設定

    S3バケットを作成したら、リモートバックエンドの設定をversions.tfファイルへ記述します。

    terraform {
      required_version = ">= 1.0.0"
    
    # 以下を追記する
      backend "s3" {
      bucket         = "remote-backend-s3-1234"
      key            = "remote-backend/terraform.tfstate"
      region         = "ap-northeast-1"
      }
    
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.3.0"
        }
      }
    }
    
    provider "aws" {
      region = "ap-northeast-1"
    }

    backendブロックの内容を解説します。

    • backend "s3": tfstateファイルを管理するバックエンドとしてAmazon S3を選択しています。
    • bucket: tfstateファイルを保存するS3バケット名を指定します。ここでは先ほど作成したバケット名を指定します。
    • key: S3バケット内でtfstateファイルが保存される具体的なパスを指定します。このパスは任意のパスを指定することができます。remote-backendフォルダの中にterraform.tfstateとして保存されます。
    • region: S3バケットが配置されているリージョンを指定します。この例ではap-northeast-1、東京リージョンを指定しています。

    ここまで完了したら、リモートバックエンドの設定を反映させるため、terraform init -migrate-stateコマンドを実行します。このコマンドを実行することで、Terraformはローカルのterraform.tfstateファイルをS3バケットにコピーし、リモートバックエンドとして設定します。

    terraform init -migrate-state
    
    Initializing the backend...
    Do you want to copy existing state to the new backend?
      Pre-existing state was found while migrating the previous "local" backend to the
      newly configured "s3" backend. No existing state was found in the newly
      configured "s3" backend. Do you want to copy this state to the new "s3"
      backend? Enter "yes" to copy and "no" to start with an empty state.
    
      Enter a value: # yes と入力

    リモートバックエンドの設定が完了すると、バックエンドs3の設定に成功した。とのメッセージが表示されます。

    Successfully configured the backend "s3"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Reusing previous version of hashicorp/aws from the dependency lock file
    - Using previously-installed hashicorp/aws v5.3.0
    
    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.tfstateファイルとterraform.tfstate.backupファイルが自動的にS3バケットに移行されるので、ローカルファイルは不要になります。移行が成功したことを確認したら、これらのローカルファイルを安全に削除することができます。

    ローカルにterraform.tfstateterraform.tfstate.backupファイルが存在しているため、2つのファイルを削除します。

    ls
    main.tf                  terraform.tfstate        terraform.tfstate.backup versions.tf
    
    rm -rf terraform.tfstate terraform.tfstate.backup

    次のセクションで、バックエンドの設定がきちんとできているか、VPCリソースを作成して確認します。

    VPCリソースの作成

    ローカルにtfstateファイルがない状態でapplyできるか確認します。

    main.tfに以下を追加します。

    # VPC
    resource "aws_vpc" "main" {
      cidr_block = "10.0.0.0/16"
      enable_dns_support = true
      enable_dns_hostnames = true
      tags = {
        Name = "main-vpc"
      }
    }
    
    # subnet
    resource "aws_subnet" "main" {
      vpc_id            = aws_vpc.main.id
      cidr_block        = "10.0.1.0/24"
      availability_zone = "ap-northeast-1a"
    
      tags = {
        Name = "main-subnet"
      }
    }

    terraform planを実行し、VPCとサブネットが作成されることが確認できたらapplyを実施します。

    terraform plan
    
    terraform apply
    
    Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

    この状態でlsコマンドを実行すると、terraform.tfstateファイルがローカルに存在しないことが分かります。

    ls
    main.tf     versions.tf

    terraform state listコマンドで、tfstateファイルに記録されているリソース一覧を取得します。

    terraform state list
    
    aws_s3_bucket.remote_backend
    aws_s3_bucket_versioning.remote_backend
    aws_subnet.main
    aws_vpc.main

    作成したリソースがtfstateファイルに記録されていることが分かります。

    これで、S3へのリモートバックエンドの設定が完了したことが確認できました。

    リソースの削除

    作成したリソースを削除するため、terraform destroyコマンドを実行します。

    terraform destroy

    S3バケットの削除ではエラーが発生します。これはS3バケットの中にオブジェクトが残っているとバケットが削除できないためです。

    Error: deleting Amazon S3 (Simple Storage) Bucket (remote-backend-s3-1234): BucketNotEmpty: The bucket you tried to delete is not empty. You must delete all versions in the bucket.

    そのため、S3バケットのみコンソール上で削除を実行します。S3バケットを削除する際は、次の順番で削除を実行します。

    • S3バケットの中身を空にする
    • S3バケットを削除する

    先述しましたが、S3バケット内にオブジェクトが残っているとバケットは削除できないため、順番に気をつけながら削除を実行しましょう。

    まとめ

    この記事では、Terraformを用いてAWS S3をリモートバックエンドとして活用し、tfstateファイルを効率的かつ安全に管理する方法について詳しく解説しました。S3のイレブンナイン(99.999999999%)の耐久性と99.99%の可用性は、tfstateファイルの安全性を保証します。

    リモートバックエンドを用いることで、チーム開発時の差分問題を解消し、作業の効率化、運用の自動化、セキュリティの強化、耐久性の向上などを実現することが可能です。

    Terraformのリモートバックエンドを使いこなし、開発の効率化とセキュリティ向上の両方を実現しましょう。

    エンベーダー編集部

    エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

    RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

    関連記事