Terraform 実行時に AssumeRole で IAM ロールにスイッチロールする方法
Terraform コマンド実行時に、AssumeRole でデプロイに必要な権限をもつ IAM ロールにスイッチロールして Terraform init
からTerraform deploy/apply/destroy
までを実行してみた
背景
- Terraform でデプロイするユーザのアクセスキーが万が一漏れても被害が最小限になるようにしたい
- 一々 AWS Cli で AssumeRole コマンド実行してアクセスキーを切り替える(上書きする)のがめんどくさいのでそうしなくていいようにしたい
- 誰がリソースをいじったかわかるようにしたい
流れ
terraform init
実行時- IAM ユーザー → S3 用 IAM ロールにスイッチ
terraform plan/deploy/destroy
実行時- IAM ユーザー → S3 用 IAM ロールにスイッチ → デプロイ用 IAM ロールにスイッチ
IAM ユーザー・ロール・ポリシーの作成
下記を作成していきます
IAM ユーザーは社員毎に用意されているものとします
AWS アカウント(アカウント ID) | IAM | 名前 | 役割 |
---|---|---|---|
Employee(111111111111) | IAM ユーザー | sample | IAM ユーザ (AssumeRole しかできない ユーザー が望ましい) |
Employee(111111111111) | IAM ポリシー | sample-service-assume-policy | IAM ユーザに AssumeRole 権限を持つ |
ServiceA(999999999999) | IAM ポリシー | sample-service-terraform-backend-policy | S3 に対する権限を持つ |
ServiceA(999999999999) | IAM ロール | sample-service-terraform-backend-role | S3 に対する権限を持つ |
ServiceA(999999999999) | IAM ロール | sample-service-terraform-deploy-role | AWS の各サービスに対する権限を持つ |
Terraform の backend ( S3 ) 用の IAM ポリシーと IAM ロールの作成
sample-service-terraform-backend-policy
を作成します。
この IAM ポリシーは Terraform が使用する state ファイルを管理する先として S3 を利用するための権限を与えるためのものになります。
その為、以下のようなポリシーを定義します。
- S3 オブジェクトの読み込みと書き込み権限
Resource
に state ファイルを管理する S3 バケットを指定
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::sample-service-terraform-tfstate/*",
"arn:aws:s3:::sample-service-terraform-tfstate"
]
}
]
}
sample-service-terraform-backend-role
を作成します。
この IAM ロールは sample-service-terraform-backend-policy
がアタッチされます。
Terraform には Backend 周りはこのロールに AssumeRole してもらい処理を行ってもらいます。
以下のように IAM ロールを定義します。
sample-service-terraform-backend-policy
をアタッチします- 信頼する相手として「対象となる IAM ユーザの AWS アカウント」を指定します
- よりセキュリティを強くするため条件を指定します
sts:RoleSessionName
でSessionName
として実行する IAM ユーザーの名前を指定するようにしますsts:ExternalId
(外部 ID) を指定します
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:RoleSessionName": "${aws:username}",
"sts:ExternalId": "sample-service-backend"
}
}
}
]
}
AssumeRole によるスイッチロール先であるデプロイ用の IAM ロールの作成
sample-service-terraform-backend-role
を作成します。
この IAM ロールは Terraform にデプロイ時に AWS の各サービスに対する権限を与えるためのものになります。
Terraform には Deploy 周りはこのロールに AssumeRole してもらい処理を行ってもらいます。
以下のように Role を定義します。
- 付与するアクセス権限を必要に応じて付与してください
- 信頼する相手として
sample-service-terraform-backend-role
を指定します- こうすることで
sample-service-terraform-backend-role
にスイッチしてる IAM ユーザーのみがスイッチできます
- こうすることで
- よりセキュリティを強くするため条件を指定します
sts:ExternalId
(外部 ID) を指定します
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::999999999999:role/sample-service-terraform-backend-role"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "sample-service-deploy"
}
}
}
]
}
IAM ユーザーに AssumeRole でデプロイ用の IAM ロールにスイッチロールできるようにする
sample-service-assume-policy
を作成します。
この IAM ポリシーは sample-service-terraform-backend-role
に Assume Role できるようにする為のものです。
その為、以下のようなポリシーを定義します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
"arn:aws:iam::999999999999:role/sample-service-terraform-backend-role"
]
}
]
}
AWS CLI の認証情報の設定と動作確認
- aws profile の編集
sample-service-terraform-backend-role
に IAM ユーザーの profile 経由でスイッチする profile を追加します。sample-service-terraform-deploy-role
にsample-service-terraform-backend-role
経由でスイッチする profile を追加します。
[default]
output = json
region = ap-northeast-1
[profile sample-service-terraform-backend]
region = ap-northeast-1
output = json
[profile sample-service-terraform-deploy]
region = ap-northeast-1
output = json
[default]
aws_access_key_id = IAM ユーザーのアクセスキー
aws_secret_access_key = IAM ユーザーのシークレットキー
[sample-service-terraform-backend]
role_arn = arn:aws:iam::999999999999:role/sample-service-terraform-backend-role
role_session_name = sample(IAM ユーザー名前)
external_id = sample-service-backend
source_profile = default
[sample-service-terraform-deploy]
role_arn = arn:aws:iam::999999999999:role/sample-service-terraform-deploy-role
external_id = sample-service-deploy
source_profile = sample-service-terraform-backend
- terraform の修正
provider
のprofile
にsample-service-terraform-deploy-role
にスイッチする profile 名を指定します。backend "s3"
のprofile
にsample-service-terraform-backend-role
にスイッチする profile 名を指定します。
terraform {
required_version = "= 0.14.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "= 3.9.0"
}
}
backend "s3" {
bucket = "sample-service-terraform-tfstate"
key = "cloudfront/terraform.tfstate"
region = "ap-northeast-1"
profile = "sample-service-terraform-backend"
}
}
provider "aws" {
profile = "sample-service-terraform-deploy"
region = "ap-northeast-1"
}
terraform init
,terraform plan/deploy/destroy
を実行してみて正常に終了すれば成功です。
Terraform 実行時に AssumeRole で IAM ロールにスイッチロールする方法おまけ
sample-service-terraform-backend-role
のスイッチに session_name の指定を強制しましたが、これをすることで Cloudtrail に以下のように出力されます。
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AAAAAAAAAAAAAAAAAAAAA:sample",
"arn": "arn:aws:sts::999999999999:assumed-role/sample-service-terraform-deploy/sample",
"accountId": "999999999999",
"accessKeyId": "BBBBBBBBBBBBBBBBBBBB",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AAAAAAAAAAAAAAAAAAAAA:sample",
"arn": "arn:aws:iam::999999999999:role/sample-service-terraform-deploy",
"accountId": "999999999999",
"userName": "sample-service-terraform-deploy"
},
"webIdFederationData": {},
"attributes": {
"mfaAuthenticated": "false",
"creationDate": "2021-03-07T14:48:29Z"
}
}
},
"eventTime": "2021-03-07T14:48:32Z",
"eventSource": "cognito-idp.amazonaws.com",
"eventName": "CreateUserPool",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "2409:10:9780:c00:f09d:5f83:7147:9b65",
"userAgent": "aws-sdk-go/1.34.26 (go1.14.5; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.14.7 (+https://www.terraform.io)",
"requestParameters": {
"poolName": "Samplece_Service_Dev",
"autoVerifiedAttributes": [
"email"
],
"usernameAttributes": [
"email"
],
principalId
に IAM ユーザーの名前が入るようになり、誰がリソースにどういった変更を加えたかなどがわかるようになります。
Terraform 実行時に AssumeRole で IAM ロールにスイッチロールする方法まとめ
アクセスキーが流出した際のことを考慮に入れたデプロイ手法は色々あり、それを試してるうちにこんな感じになりました。
profile の設定を半ば強制してる感じで設定も共有する必要がありますがアクセスキーと profile の設定さえ教えればアクセスキーの上書きなど細々としたことやらずに済むので楽かなということでこれで運用してみようかなと思ってます。
個人開発したサービス
個人開発したサービス
目次
個人開発したサービス