🎉

aws-vaultでMFAを有効にしながらterraformを使う準備をしよう

2023/07/02に公開

想定する読者

・terraformを初めて使う人

1. terraformコマンドを使う準備

brew install terraform

2. 安全にterraformコマンドを使うためにロールを作ってMFAを有効にしよう

terraformはコマンド一つでインフラの作成・削除ができてしまうので、権限管理をしっかりするべきです。awsで権限を管理するときにはロールを作成します。そのロールにassume roleしたときにだけterraformコマンドが打てるようにし、assume roleする際にはMFA(Multi-factor authentication)を有効にしましょう。

話が長くなりましたが、上記を実現するためには下記を行います。

  1. terraform実行用ロールを作成
  2. aws-vaultを準備

2-1. terraform実行用ロールを作成

まず前提としてMFAを有効にしたIAMユーザーを用意します。(以降iam1と呼びます)

terraform実行用ロールを作成します。今回は特に用途を限定しないのでAdministratorAccessを付与しrole名はterraformとしておけばいいと思います。ポイントはMFAを必須にすることです。そうすことで下記のように条件(
(Conditionの部分)がつき、MultiFactorAuthPresent: trueとなります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxx:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

次にiam1がterraformロールにassume roleできるようにするために下記を追加します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::xxxxxxxxxx:role/terraform",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

2-2. aws-vaultを準備

aws-vaultを使うことで、terraformコマンドを使用する際にもMFAコマンドを有効にすることができます。
ゴールは下記のようにコマンドが打てることです。

aws-vault exec terraform_user  -- terraform init 

aws-vaultの設定方法はこちらをみてください。
https://github.com/99designs/aws-vault

私の~/.aws/configはこうなっています。

~/.aws/config
 [profile default]
 
 [profile terraform_user]
 source_profile=default
 mfa_serial=arn:aws:iam::xxxxxxxxxxxx:mfa/iam1
 role_arn=arn:aws:iam::xxxxxxxxxxxx:role/terraform
 region=ap-northeast-1

terraform initを実行しよう

terraform initはこれからterraformを使うにあたって、設定を行うためのコマンドです。
terraform initは下記ファイルを置いているディレクトリで実行します。

main.tf

terraform {
  required_version = ">=1.4.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }

  ### この部分はまずコメントアウトします。
  # backend "s3" {
    # bucket = "terraform-state-2023-07-02"
    # region = "ap-northeast-1"
    # key = "terraform.tfstate"
  # }
  ###

}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "terraform-state-2023-07-02"
  versioning {
    enabled = true
  }
}

コメントアウトしている部分は、terraform initしたときに作成されるtfstateというterraform管理しているリソースの状況を記録するファイルをs3でも管理するために記述するものですが、最初のterraform init時にはそのs3がないためコメントアウトします。

terraform planを実行しよう

terraform initを実行した後はterraform planを実行しましょう。terraformはリソースの作成・削除が簡単に行えてしまうため、実行前に何が起きるかをterraform planで確認することができます。

aws-vault exec terraform_user  -- terraform plan 

実行ログに下記が出ますので、s3が1つ追加されるのだなとわかります。

Plan: 1 to add, 0 to change, 0 to destroy.

terraform applyを実行しよう

terraform planで影響範囲を確認したらterraform applyを実行しましょう。

aws-vault exec terraform_user  -- terraform apply 

AWS マネジメントコンソールからs3の存在を確認できたらOKです。

tfstateをs3管理しよう

tfstateはgit管理でもいいのですが、複数ブランチで異なる操作をするときはコンフリクトが起きて困るためs3管理しましょう。

main.tf

terraform {
  required_version = ">=1.4.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>3.0"
    }
  }

  ### この部分のコメントアウトをはずします。
  backend "s3" {
    bucket = "terraform-state-2023-07-02"
    region = "ap-northeast-1"
    key = "terraform.tfstate"
  }
  ###

}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "terraform-state-2023-07-02"
  versioning {
    enabled = true
  }
}

その後で下記を実行します。

aws-vault exec terraform_user  -- terraform init 

これでtfstateをs3管理できるようになりました。

Discussion