かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

tfenv+aws-vault+direnv を組み合わせて Windows 上に Terraform の実行環境を構築する

概要

記事一覧はこちらです。

Windows 上に Terraform の実行環境を構築します。access key ID, secret access key は環境変数やテキストファイルに平文で設定・記述するのではなく Windows の資格情報マネージャーに登録します。また MFA を利用していなければ実行できないようにします。

  • Terraform は exe を直接ダウンロードするのではなく tfenv を利用してインストールします。
  • aws-vault を利用して access key ID, secret access key を Windows の資格情報マネージャーに登録します。
  • access key ID, secret access key を発行する IAM ユーザには ReadOnlyAccess ポリシーだけ付与します。
  • AdministratorAccess ポリシーを付与した IAM ロールを作成し、terraform 実行時にスイッチロールします。
  • IAM ロールへスイッチロールできる IAM ユーザは IAM ポリシーで制限します。また MFA を利用していなければスイッチロールできないようにします。
  • direnv をインストールして、ディレクトリ毎に実行する access key ID, secret access key(実際にはプロファイル)を切り替えられるようにします。

またタイトルには記述していませんが Git for Windows をインストールして git-cmd.exe+bash.exe が起動できることが前提です(tfenv のページに Windows (64bit) - only tested in git-bash - currently presumed failing due to symlink issues in git-bash という記述があります)。この記事では git-cmd.exe+bash.exe を D:\git\git-cmd.exe --command=usr/bin/bash.exe -l -i コマンドで起動しています。

参照したサイト・書籍

  1. Terraform
    https://www.terraform.io/

  2. tfutils/tfenv
    https://github.com/tfutils/tfenv

  3. 99designs/aws-vault
    https://github.com/99designs/aws-vault

  4. direnv/direnv
    https://github.com/direnv/direnv

  5. MFA 保護 API アクセスの設定
    https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html

目次

  1. tfenv と terraform をインストールする
  2. IAM ユーザと IAM ロールを作成する
  3. aws-vault をインストールして Windows の資格情報マネージャーに access key ID, secret access key を登録する
  4. C:\Users\<ユーザ名>\.aws\config に設定を追加する
  5. direnv をインストールする
  6. C:\Users\<ユーザ名>\.bashrc に設定を追加する
  7. ディレクトリに移動したら terraform 実行時に使用する aws の profile を自動で切り替えるよう設定する
  8. Windows の資格情報マネージャーに保存した access key ID, secret access key は --no-session オプション付きで aws-vault を実行すれば取得できる

手順

tfenv と terraform をインストールする

tfutils/tfenv の Releases ページ(https://github.com/tfutils/tfenv/releases)から Latest release のラベルが付いている v1.0.2 の「Source code(zip)」のリンクをクリックして tfenv-1.0.2.zip をダウンロードします。

f:id:ksby:20200118125547p:plain

ダウンロードが完了したら tfenv-1.0.2.zip を解凍し、フォルダ名を tfenv に変更後 D:\ の下に移動します。

f:id:ksby:20200118130433p:plain

環境変数 Path に D:\tfenv\bin\ を追加した後、git-cmd.exe+bash.exe を起動して tfenv コマンドが実行できることを確認します。

f:id:ksby:20200118133227p:plain

以下のコマンドを実行して、terraform の最新バージョンを確認してからインストールします。

  • tfenv list-remote | head
  • tfenv install 0.12.19
  • tfenv list

f:id:ksby:20200118133557p:plain

terraform -version コマンドを実行すると 0.12.19 が表示されます。

f:id:ksby:20200118133829p:plain

起動した git-cmd.exe+bash.exe を終了します。

IAM ユーザと IAM ロールを作成する

一時作業用の AdministratorAccess ポリシーを付与した IAM ユーザを作成して、access key ID, secret access key を発行します。

IAM ユーザと IAM ロールの作成には terraform を利用します。作業用に D:\work\ ディレクトリを新規作成します。その下に main.cf というファイルを新規作成して、以下の内容を記述します。

terraform {
  required_version = "0.12.19"
}

provider "aws" {
  region = "ap-northeast-1"
}

///////////////////////////////////////////////////////////////////////////////
// ReadOnlyUser
//
resource "aws_iam_user" "ReadOnlyUser" {
  name = "ReadOnlyUser"
  // MFAデバイスを登録していると削除できないので forace_destroy を true にしている
  force_destroy = true
}
resource "aws_iam_user_policy_attachment" "AttachReadOnlyAccessToReadOnlyUser" {
  user       = aws_iam_user.ReadOnlyUser.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

///////////////////////////////////////////////////////////////////////////////
// AdminRole
//
data "aws_iam_policy_document" "SwitchAdminRolePolicy" {
  statement {
    effect = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type        = "AWS"
      identifiers = [aws_iam_user.ReadOnlyUser.arn]
    }
    condition {
      test     = "Bool"
      variable = "aws:MultiFactorAuthPresent"
      values   = [true]
    }
  }
}
resource "aws_iam_role" "AdminRole" {
  name               = "AdminRole"
  assume_role_policy = data.aws_iam_policy_document.SwitchAdminRolePolicy.json
}
resource "aws_iam_role_policy_attachment" "AdminRole" {
  role       = aws_iam_role.AdminRole.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

git-cmd.exe+bash.exe を起動した後、カレントディレクトリを D:\work\ に変更してから環境変数 AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY に AdministratorAccess ポリシーを付与した一時作業用の IAM ユーザの access key ID, secret access key を設定します。

f:id:ksby:20200118183941p:plain

terraform init コマンドを実行してから、

f:id:ksby:20200118184308p:plain

terraform planterraform apply コマンドを実行して IAM ユーザ(ReadOnlyUser)、IAM ロール(AdminRole)を作成します(画面キャプチャは terraform apply の一部のみ)。

f:id:ksby:20200118184725p:plain f:id:ksby:20200118184843p:plain

AWS マネジメントコンソールから一時作業用の IAM ユーザでサインインし、作成した IAM ユーザ(ReadOnlyUser)の「コンソールへのアクセスの有効化」「MFA デバイスの割り当て」「アクセスキーの作成」を行います(詳細な手順は省略します)。

f:id:ksby:20200118195818p:plain

MFA の ARN、access key ID, secret access key は後の設定で使用するのでメモしておきます。

f:id:ksby:20200118200239p:plain

作成した IAM ロール(AdminRole)のロール ARN も後の設定で使用するのでメモしておきます。

f:id:ksby:20200118202842p:plain

起動した git-cmd.exe+bash.exe を終了します。

一時作業用の IAM ユーザの access key ID, secret access key は削除します。一時作業用の IAM ユーザも不要なら削除します。

aws-vault をインストールして Windows の資格情報マネージャーに access key ID, secret access key を登録する

99designs/aws-vault の Releases ページ(https://github.com/99designs/aws-vault/releases)から Latest release のラベルが付いている v5.1.2 の「aws-vault-windows-386.exe」のリンクをクリックして aws-vault-windows-386.exe をダウンロードします。

D:\ の直下に aws-vault ディレクトリを作成し、ダウンロードした aws-vault-windows-386.exe を移動して aws-vault.exe にリネームします。

f:id:ksby:20200118194852p:plain

環境変数 Path に D:\aws-vault\ を追加した後、git-cmd.exe+bash.exe を起動して aws-vault コマンドが実行できることを確認します。

f:id:ksby:20200118195015p:plain

aws-vault add ReadOnlyUser コマンドを実行して IAM ユーザ(ReadOnlyUser)の access key ID, secret access key を Windows の資格情報マネージャーに登録します。

f:id:ksby:20200118201341p:plain

登録すると「資格情報マネージャー」の「Windows 資格情報」-「汎用資格情報」に aws-vault:aws-vault:ReadOnlyUser が追加されます。

f:id:ksby:20200118201756p:plain

起動した git-cmd.exe+bash.exe を終了します。

C:\Users\<ユーザ名>\.aws\config に設定を追加する

C:\Users\<ユーザ名>\.aws\config をエディタで開いて aws-vault の Roles and MFA の記述を参考に設定を追加します。

[default]
output=json
region=ap-northeast-1

[profile ReadOnlyUser]
mfa_serial = arn:aws:iam::123456789012:mfa/ReadOnlyUser

[profile AdminRole]
source_profile = ReadOnlyUser
role_arn = arn:aws:iam::999999999999:role/AdminRole
mfa_serial = arn:aws:iam::123456789012:mfa/ReadOnlyUser
  • aws-vault add ReadOnlyUser コマンドを実行した時に [profile readonlyuser] が追加されているので、readonlyuserReadOnlyUser に変更した後(IAM ユーザが大文字小文字を区別しないと知ったのはこのページを書いた後でした。。。) mfa_serial = ... の行を追加します。
  • [profile AdminRole] の設定を追加します。
  • mfa_serial = ... はどちらにも ReadOnlyUser の MFA の ARN を記述します。

一旦ここで動作確認します。git-cmd.exe+bash.exe を起動してから aws-vault exec AdminRole -- aws s3 mb s3://<何か適当なBucket名> を実行して S3 Bucket を作成してみます。

f:id:ksby:20200118210058p:plain

初回の実行時には MFA の token が求められますので MFA デバイスで確認して入力します。この時 temporary security credentials が取得されますので2回目以降のコマンド実行では token の入力は求められません。temporary security credentials の有効期限はデフォルトで 1時間です(一時的なセキュリティ認証情報のリクエスト に記載があります)。

取得された temporary security credentials も Windows の資格情報マネージャーに登録されます。

f:id:ksby:20200118210956p:plain

有効期限が切れるか、これを削除すると再び MFA の token が求められます。

temporary security credentials を Windows の資格情報マネージャーに保存したくない場合(コマンド実行時に都度 MFA の token を求めるようにしたい場合)には、--no-session オプションを追加して aws-vault exec AdminRole --no-session -- aws s3 mb s3://<何か適当なBucket名> のようにコマンドを実行します。

作成した S3 Bucket は削除します。

f:id:ksby:20200118211238p:plain

起動した git-cmd.exe+bash.exe を終了します。

direnv をインストールする

direnv/direnv の Releases ページ(https://github.com/direnv/direnv/releases)から Latest release のラベルが付いている v2.20.0 の「direnv.windows-amd64.exe」のリンクをクリックして direnv.windows-amd64.exe をダウンロードします。

f:id:ksby:20200118212921p:plain f:id:ksby:20200118213050p:plain

D:\ の直下に direnv ディレクトリを作成し、ダウンロードした direnv.windows-amd64.exe を移動します(リネームはしません)。

f:id:ksby:20200118213357p:plain

C:\Users\<ユーザ名>\.bashrc に設定を追加する

C:\Users\<ユーザ名>\.bashrc をエディタで開いて設定を追加します。

# for direnv
alias direnv="/d/direnv/direnv.windows-amd64.exe"
_direnv_hook() {
  local previous_exit_status=$?;
  eval "$(MSYS_NO_PATHCONV=1 direnv export bash | sed 's|export PATH=|export _X_DIRENV_PATH=|g')";
  if [ -n "$_X_DIRENV_PATH" ]; then
    _X_DIRENV_PATH=$(cygpath -p "$_X_DIRENV_PATH")
    export "PATH=$_X_DIRENV_PATH"
    unset _X_DIRENV_PATH
  fi
  return $previous_exit_status;
};

if ! [[ "$PROMPT_COMMAND" =~ _direnv_hook ]]; then
  PROMPT_COMMAND="_direnv_hook;$PROMPT_COMMAND"
fi

# for aws-vault+terraform
tf() {
  aws-vault exec $AWS_PROFILE -- bash -c "terraform $@"
}
  • alias direnv="/d/direnv/direnv.windows-amd64.exe" を追加します。
  • _direnv_hook() { ... }if ! [[ "$PROMPT_COMMAND" =~ _direnv_hook ]]; then ... fi を追加します。Setup に記載されている BASH 用の eval "$(direnv hook bash)" の設定だと git-cmd.exe+bash.exe の環境で direnv の PATH_add が実行された時にパスが正しく設定されないので、PATH gets mangled when using direnv from git-bash on Windows に記載されていたコードを設定しています。
  • aws-vault+terraform の実行用に tf() { ... } を追加します。環境変数 AWS_PROFILE に使用するプロファイルを設定してから、terraform apply ならば tf apply のように terraformtf に変更したコマンドを実行します。bash -c "terraform $@"aws-vault exec can not successfully run with eval を参考にしました。また動作確認等で素の terraform コマンドを使う分けたりする必要性を感じなければ、関数名を tf()terraform() に変えても構いません。その場合 terraform コマンドを実行するとこの関数が実行されるようになります。

ディレクトリに移動したら terraform 実行時に使用する aws の profile を自動で切り替えるよう設定する

D:\work2\ を作成し、その下に .envrc と main.cf を作成して VPC を1つ作成してみます。

D:\work2\ を作成してから git-cmd.exe+bash.exe を起動してカレントディレクトリを D:\work2\ に変更します。touch .envrc コマンドを実行して .envrc を作成してから、

f:id:ksby:20200118230829p:plain

以下の内容を記述します。

export AWS_PROFILE=AdminRole

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

terraform {
  required_version = "0.12.19"
}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_vpc" "sample-vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "sample-vpc"
  }
}

direnv allow コマンドを実行します。

f:id:ksby:20200118232658p:plain

tf init コマンドを実行してから、

f:id:ksby:20200118233401p:plain

tf plantf apply コマンドを実行すると VPC が作成されました。

f:id:ksby:20200118235726p:plain

tf destroy コマンドを実行して作成した VPC を削除します。

.envrc を以下の内容に変更すると、

export AWS_PROFILE=ReadOnlyUser

tf apply コマンドを実行してもエラーとなり VPC は作成できません。

f:id:ksby:20200119001133p:plain f:id:ksby:20200119001242p:plain

Windows の資格情報マネージャーに保存した access key ID, secret access key は --no-session オプション付きで aws-vault を実行すれば取得できる

Windows の資格情報マネージャーに保存された access key ID, secret access key を後から取得することはできないのか調べたところ、aws-vault exec ReadOnlyUser --no-session -- env | grep ^AWS コマンドを実行すれば取得できます。

下の画像の例では、temporary security credentials ではなく ReadOnlyUser の access key ID, secret access key が表示されています。

f:id:ksby:20200119030418p:plain

IAM ユーザには極力権限を付与せず(ReadOnlyAccess ポリシーも外してよいかもしれません)、強い権限はスイッチロール先の IAM ロールに与える(MFA も有効にする)方が良さそうです。

履歴

2020/01/19
初版発行。