クラウド環境の構成管理ツールとしてIaCを使う場合、GitHub ActionsやAWS CodeBuildなどを活用することで構成管理を自動化して運用の安定性を高めることができます。
しかし、CI/CDパイプラインが権限不足でコケるというのはあるあるなのではないでしょうか(ぼくは稀によくにやります)
特にリポジトリの初期化や、CI/CD周りの仕組みを改修する際、修正のコミットを多く重ねて何度もトライ&エラーする必要が出るハメになったり・・・。
上記の悩みを解決するTipsを紹介します。
本記事ではAWSの利用を前提とします。
TL;DL - AWS Providerのassume_roleを使おう
provider "aws"
の設定にassume_role
セクションを追加します。
provider "aws" {
region = "ap-northeast-1"
+ assume_role {
+ role_arn = "arn:aws:iam::12345678910:role/role-to-assume"
+ }
}
これを使うとterraform plan
やterraform apply
の実行時に内部的にロールを切り替えて(assume role)処理を続行します。
切り替えた後のロールに権限不足がある場合、その時点で気づける可能性があります。しかし、これでも絶対に防げるとは限りません…。
通常CI/CDを自動化している場合、原則はローカルでterraform apply
は実行せずterraform plan
を確認するのみ、という運用ルールが考えられます。
terraform plan
とapply
とでは実際に実行するアクションは異なるため、やはり権限不足の可能性は残ることになります。
設定方法
上述のassume_role
に指定するIAMロールの作成方法も紹介します。
前提知識:IAMロールの信頼関係
AWS IAMにおいて「あるIAMユーザー or ロールが別のロールを使用する(= 引き受ける)」操作はAssume Roleと呼ばれます。
Assume Roleを実現するために必要な設定が信頼関係(または信頼ポリシー)で、引き受ける対象のロールに設定します。
サンプルコード
このようなIAMロールをTerraformで作成する例です。
ローカル作業用にIAMユーザー(kokado-iam-user
)を使っているケースを考えます。
参考 - terraform-aws-modules/iam/aws | iam-assumable-role Submodule | Terraform Registry
data "aws_caller_identity" "current" {}
# --- 信頼ポリシーに設定する「Assume Role可能な(= 信頼できる)IAMユーザー」
data "aws_iam_user" "user" {
user_name = "kokado-iam-user"
}
# --- terraform plan/apply の中で切り替えるIAMロールを定義する
module "role_to_assume_for_cicd" {
source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
create_role = true
role_name = "role-to-assume-for-cicd"
role_requires_mfa = false
trusted_role_arns = [
# 1. ローカル用のIAMユーザーを信頼する
data.aws_iam_user.user.arn,
# 2. ここで作成するロール自体も信頼する(自己信頼)
"arn:aws:iam::${data.aws_caller_identity.current}:role/role-to-assume-for-cicd",
]
custom_role_policy_arns = [
# Assume Roleの際に iam:GetUser が必要であるため追加
"arn:aws:iam::aws:policy/IAMReadOnlyAccess",
# 以降は構成管理に必要なポリシーを追加する
# arn:aws:iam::aws:policy/AmazonS3FullAccess,
# ...
]
}
2. ここで作成するロール自体も信頼する(自己信頼)
の解説は割愛します。詳しくは以下をご覧ください。
参考 - [仕様変更] IAM ロール信頼ポリシーの挙動が変更になり IAM ロールの「暗黙的な自己信頼」がなくなりました | DevelopersIO
なお、このIAMロール自体は事前に手動で作成しておくといった準備が必要です。
最後に動作確認です。
data "aws_caller_identity" "current" {}
output "caller_identity" {
value = data.aws_caller_identity.current.arn
}
簡単ですが、上記のコードを実行すると、outputで使用中の認証情報がIAMユーザーではなくassumed-role`に変わることが確認できます。
$ terraform plan
data.aws_caller_identity.current: Reading...
...
module.role_to_assume_for_cicd.aws_iam_role_policy_attachment.custom[0]: Refreshing state... [id=role-to-assume-for-cicd-20231206153119131500000001]
Changes to Outputs:
+ caller_identity = "arn:aws:sts::12345678910:assumed-role/role-to-assume-for-cicd/aws-go-sdk-xxx"