コンテンツにスキップ

設定ファイル@Terraform

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. バックエンド内のファイル

tfstateファイル

tfstateファイルとは

実インフラのインフラの状態が定義されたjsonファイルのこと。

バックエンドの場所に限らず、terraform applyコマンドを実行した後、成功もしくは失敗したタイミングで初めて作成される。

tfstateファイル間では、Terraformやプロバイダーのバージョンに差が開きすぎると、互換性がなくなる。

{
  "version": 4,
  "terraform_version": "1.0.0",
  "serial": 3,
  "lineage": "*****-*****-*****-*****-*****",
  "outputs": { # outputブロックのapplyで追加される。
    "foo_ids": {
      "value": "*****",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "data", # dataブロックのapplyで追加される。
      "type": "aws_caller_identity", # resourceタイプ
      "name": "current", # リソース名
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [ # 設定値
        {
          "schema_version": 0,
          "attributes": {
            "account_id": "<AWSアカウントID>",
            "arn": "*****",
            "id": "*****",
            "user_id": "*****"
            ...
          },
          "sensitive_attributes": []
        }
      ]
    },
    {
      "module": "module.ec2", # moduleブロックの場合に追加される。
      "mode": "managed", # importや、resourceブロックのapplyで追加される。
      "type": "aws_instance", # resourceタイプ
      "name": "bastion", # リソース名
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [ # 設定値
        {
          "schema_version": 0,
          "attributes": {
            "arn": "*****",
            "name": "prd-foo-instance",
            "tags": {
              "Env": "prd",
              "ManagedBy": "terraform",
              "Repository": "https://github.com/*****"
            },
            "description": "*****",
            ...
          }
        }
      ]
    }
  ]
}

state.lockファイル

tfstateファイルの競合を防ぐために、terraform applyコマンドの処理中にtfstateファイルはロックされる。

ロックの状態は、state.lockファイルやクラウドプロバイダーのDB (例:DynamoDB) に記載する。

terraform applyコマンドが完了すれば、ロックは解除される。

ロックされている間、他のユーザーは一連のterraformコマンドを実行できなくなる。

▼ 残骸ロックの解除方法

terraform applyコマンドの完了前に処理を強制的に中断してしまうと、ロックが残ってしまう。

これが起こると、以降、一連のterraformコマンドを実行できなくなってしまう。

$ terraform plan
Acquiring state lock. This may take a few moments...

Error: Error acquiring the state lock
Error message: resource temporarily unavailable
Lock Info:
   ID:        89e54252-fef0-2a68-17bf-e0bb411ff1e3 # これを使用する
   Path:      terraform.tfstate
   Operation: OperationTypeInvalid
   Who:       hiroki-hasegawa
   Version:   1.1.5
   Created:   2022-02-21 06:26:07.435925 +0000 UTC
   Info:

その場合、terraform force-unlockコマンドでIDを指定すれば、ロックを解除できる。

$ terraform force-unlock 89e54252-fef0-2a68-17bf-e0bb411ff1e3


.terraform.lock.hclファイル

.terraform.lock.hclファイルとは

terraformブロックの設定に基づいて、開発者間で共有する必要がある情報 (バージョン、ハッシュ値、など) が設定される。

これにより例えば、他の人がリポジトリを使用する時に、異なるプロバイダーを宣言できないようになる。

もし、異なるプロバイダーを使用したい場合は、以下のコマンドを実行する。

これにより、.terraform.lock.hclファイルのアップグレード/ダウングレードが実行される。

.terraform.lock.hclファイルを更新してアップグレードするには、-upgradeオプションが必要である。

$ terraform init -upgrade

▼ version

プロバイダーのバージョンを設定する。

provider "registry.terraform.io/hashicorp/aws" {

  ...

  version = "4.3.0"

  ...

}

▼ constraints

provider "registry.terraform.io/hashicorp/aws" {

  ...

  constraints = ">= 3.19.0"

  ...

}

▼ hashes

ハッシュ値を設定する、タグごとに役割が異なる。

provider "registry.terraform.io/hashicorp/aws" {

  ...

  hashes = [
    "h1:*****",
    "h1:*****",
    "zh:*****",
    ...
  ]

  ...

}
タグ名 説明
h1 開発者が使用しているOSを表すハッシュ値を設定する。zhタグのzipパッケージのOS名に存在しないOS値が、h1タグに設定されている場合、通信中に改竄されたと見なされ、エラーになってしまう。
zh プロバイダーのzipパッケージ (terraform-provider-aws_<バージョン>_<OS名>) のチェックサムハッシュ値を設定する。h1タグのOS値に存在しないOS名のzipパッケージが、zhタグに設定されている場合、通信中に改竄されたと見なされ、エラーになってしまう。


02. ホームディレクトリ (~/) 内のファイル

~/.terraformrcファイル

.terraformrcファイルとは

terraformコマンドの実行者のみに適用する動作を設定する。

▼ plugin_cache_dir

最初のterraform initコマンド時に、プロバイダープラグインのキャッシュを作成する。

以降、プロバイダープラグインをインストールする必要がなくなり、terraform initコマンドの速度を改善できる。

# ~/.terraformrcファイル

plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"


03. 認証情報

必要な情報

terraformコマンドでクラウドプロバイダーとパケットを送受信ためには、クラウドプロバイダーへの認可スコープが必要にある。


設定方法

▼ ハードコーディングによる設定

リージョンの他、アクセスキーIDとシークレットアクセスキーをハードコーディングで設定する。

誤ってコミットしてしまう可能性があるため、ハードコーディングしないようにする。

*実装例*

# @ルートモジュール

terraform {
  required_version = "1.3.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.0"
    }
  }

  backend "s3" {
    bucket     = "prd-foo-tfstate-bucket"
    key        = "terraform.tfstate"
    region     = "ap-northeast-1"
    # アクセスキーID
    access_key = "*****"
    # シークレットアクセスキー
    secret_key = "*****"
  }
}

provider "aws" {
  region     = "ap-northeast-1"
  # アクセスキーID
  access_key = "*****"
  # シークレットアクセスキー
  secret_key = "*****"
}

▼ 認証情報ファイルによる設定

認証情報は、~/.aws/credentialsファイルに記載されている。

# 標準プロファイル
[default]
aws_access_key_id=*****
aws_secret_access_key=*****

# 独自プロファイル
[bar-profile]
aws_access_key_id=*****
aws_secret_access_key=*****

認証情報ファイルを読み出し、プロファイル名を設定することにより、認証情報を参照できる。

*実装例*

# @ルートモジュール

terraform {
  required_version = "1.3.0"

  required_providers {

    aws = {
      source  = "hashicorp/aws"
      version = "3.0"
    }
  }

  # 認証情報ファイルから、アクセスキーID、シークレットアクセスキーを読み込む
  backend "s3" {
    # バケット名
    bucket                  = "prd-foo-tfstate-bucket"
    # tfstateファイル名とバケット内ディレクトリ構造
    key                     = "terraform.tfstate"
    region                  = "ap-northeast-1"
    # 認証情報ファイルへのパス
    shared_credentials_file = "$HOME/.aws/credentials"
    # 認証情報ファイルのプロファイル名
    profile                 = "bar-profile"
  }
}

# 認証情報ファイルから、アクセスキーID、シークレットアクセスキーを読み込む
provider "aws" {
  region                  = "ap-northeast-1"
  profile                 = "foo"
  shared_credentials_file = "$HOME/.aws/<認証情報ファイル名>"
}

▼ 環境変数による設定

認証情報ファイルではなく、exportコマンドを使用して、必要な情報も設定できる。

参照できる環境変数名は決まっている。

# regionの代わり
$ export AWS_DEFAULT_REGION="ap-northeast-1"

# access_keyの代わり
$ export AWS_ACCESS_KEY_ID="*****"

# secret_keyの代わり
$ export AWS_SECRET_ACCESS_KEY="*****"

# profileの代わり
$ export AWS_PROFILE="bar-profile"

# tokenの代わり (AWS STSを使用する場合)
$ export AWS_SESSION_TOKEN="*****"

環境変数を設定すると、値がproviderブロックに自動的に出力される。

CircleCIのような、一時的に環境変数が必要になるような状況では有効な方法である。

# @ルートモジュール

terraform {
  required_version = "1.3.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.0"
    }
  }

  # リージョン、アクセスキーID、シークレットアクセスキーは不要
  backend "s3" {
    bucket  = "<バケット名>"
    key     = "<tfstateファイル名とバケット内ディレクトリ構造>"
  }
}

# 環境変数から、リージョン、アクセスキーID、シークレットアクセスキー、を読み込む
# リージョン、アクセスキーID、シークレットアクセスキー、の設定は不要
provider "aws" {}