本記事は、こちらの記事のCross postです。
はじめに
Terraformは、インフラ構成をCodeで管理(IaC)したり、同様の環境を複数構築するのに便利なツールである。
しかし、Terraform用のCredentialを対象の各AWSアカウントから払い出せればスムーズだが、Security要件によってはそれが難しいケースもある。例えば、AWS ConsoleにLog-inするIAM Userを用いなければならなかったり、そのIAM UserにはMFAが義務付けられていたり、Switch role(Assume role)を用いてTerraformで使用するCredentialが無いアカウントに環境を構築しなければならないケースなどである。
このような少し複雑な構成の場合、Terraformの設定やApplyにはちょっとしたコツが必要となる。本記事では、そのようなTipsをまとめておきたい。
前提条件
今回は、以下のような構成おいて、TerraformでAWS Account B
下に構築を行うことを想定する。
- AWS Account Aについて、Terraform実行するIAM UserのCredentialが払い出されている
- AWS Account BにはSwitch role(Assume role)用のRoleが設定されており、上記のAWS Account AのIAM UserからSwitch role(Assume role)できるようになっている
- 上記のAWS Account AのIAM UserのCredentialにはMFAが設定されている
事前準備
- AWS Cliのインストール
- AWSのCredentialの払い出し
設定方法
MFAを使うための方法
AWC Cli
[profile Account-A]
region = ap-northeast-1
output = text
mfa_serial = arn:aws:iam::123456789012:mfa/aws_cli
ポイントは、mfa_serial
の部分。
ここに、Credential情報に紐づくMFAのARNを記述する。
ちなみに、本記事執筆時点では AWS CliのMFAにPassskeyは使用できない1ので、必ず認証アプリケーション
を割り当てておく必要がある。
以下にSampleの設定ファイルを置いておく。
https://github.com/unitedstar-tech/common/blob/main/terraform_mfa/aws_config.sample
MFA使用環境下でTerraformを使う
結論から言うと、Terraform自体はMFAトークンによる対話型認証に対応していない。
そのため、AWS Cliのようにshared_config_files
の設定を用いてTerraformを利用することはできない。
そこで、Wrapper scriptを作成した。
https://github.com/unitedstar-tech/common/blob/main/terraform_mfa/terraform_mfa
Source
#!/bin/bash
export LANG=C
# ARGS
MFA_ARN="arn:aws:iam::123456789012:mfa/aws_cli"
SRC_PROFILE="Account-A"
VALID_DURATION="14400"
check_opts=0
while getopts "m:t:h" opt
do
case $opt in
m)
MFA_CODE=$OPTARG
check_opts=`expr $check_opts + 1`;;
t)
TERRAFORM_MODE=$OPTARG
check_opts=`expr $check_opts + 2`;;
h)
echo "Usage: $0 [-m MFA_CODE] [-t TERRAFORM_ARGS]"
exit 0;;
\?)
echo "[WARNING] Usage: $0 [-m MFA_CODE] [-t TERRAFORM_ARGS]";;
esac
done
if [ $check_opts -ne 3 ]
then
echo -e "[ERROR] Missing required options\n\nUsage: $0 [-m MFA_CODE] [-t TERRAFORM_ARGS]\n-h to see Help"
exit 1
fi
# Main
DATA=`aws sts get-session-token --serial-number $MFA_ARN --profile $SRC_PROFILE --duration-seconds $VALID_DURATION --token-code $MFA_CODE`
if [ $? -ne 0 ]
then
echo "[ERROR] Invalid MFA code"
exit 1
fi
ACCESS_KEY=`echo $DATA | awk '{print $2}'`
SECRET_ACCESS_KEY=`echo $DATA | awk '{print $4}'`
TOKEN=`echo $DATA | awk '{print $5}'`
export AWS_ACCESS_KEY_ID=$ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY
export AWS_SESSION_TOKEN=$TOKEN
terraform $TERRAFORM_MODE
具体的な方式としては、AWS Security Token Service(AWS STS)にMFA One-time codeとCredential情報を渡すことでIAMの一時的な認証情報(Token)を払い出し2、そのTokenを環境変数にSetして認証に用いることでTerraformがMFA One-time Codeの入力なしに実行することを可能としている。
Usage
e.g.
# terraform_mfa -t "plan -target=aws_vpc.vpc" -m <MFAのOne-time code>
Switch role(Assume role)を使うための方法
AWS Cli
[profile Account-A]
region = ap-northeast-1
output = text
mfa_serial = arn:aws:iam::123456789012:mfa/aws_cli
[profile Account-B]
role_arn = arn:aws:iam::987654321098:role/AWSAdministratorAccess
source_profile = Account-A
region = ap-northeast-1
output = text
mfa_serial = arn:aws:iam::123456789012:mfa/aws_cli
ポイントは、source_profile
にSwitch role(Assume role)元のProfileを、role_arn
にSwitch role(Assume role)先のRole arnを設定する。
source_profile
にMFAが設定されている場合、Switch role(Assume role)先のEntryにも同様にmfa_serial
を設定する必要がある。
Terraform
Source
まずは、Terraformを使うための設定を記述したTFファイル全文を掲載しておく。
ポイントとなる部分の解説は後述。
terraform {
required_version = ">= 1.10.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.33.0"
}
}
backend "s3" {
bucket = "terraform-state-dev-987654321098-ap-northeast-1"
key = "dev/terraform.tfstate"
region = "ap-northeast-1"
assume_role = {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
}
}
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
}
provider "aws" {
alias = "tokyo"
region = "ap-northeast-1"
assume_role {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
}
provider "aws" {
alias = "osaka"
region = "ap-northeast-3"
assume_role {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
ポイントは、provider
Block.
ここに、assume_role
でSwitch role(Assume role)先のRoleのARNを記述する。
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
}
tfstateをSwitch role(Assume role)先のS3に配置する
backend "s3" {
bucket = "terraform-state-dev-987654321098-ap-northeast-1"
key = "dev/terraform.tfstate"
region = "ap-northeast-1"
assume_role = {
role_arn = "arn:aws:iam::987654321098:role/AWSAdministratorAccess"
}
ポイントは、backend
Blockのassume_role
セクション。
ここに、assume_role
でSwitch role(Assume role)先のRoleのARNを記述する。
なお、provider
Blockと違い、backend
Blockでは "assume_role"の後ろに"="が入ることに注意が必要。
終わりに
以上のように、TerraformでMFAやSwitch role(Assume role)を扱う方法や要点をまとめた。
Webで検索すると、aws-vaultを用いる方法なども頻繁に紹介されているが、pass
やGnuPG
と言った依存モジュールも導入する必要があり、やや煩雑である。
少し複雑な環境においてより手軽にTerraformで扱うために、本記事が参考になれば幸いである。
参考記事