🦅

Assume Roleを使ったTerraform実行で、Assume Role元のユーザ情報をCloudTrailに記録する方法

2025/01/27に公開

はじめに

TerraformでAWSリソースを操作する時に設定するproviderですが、以下が基本となります。

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

この設定は基本ではあるものの、ローカルの認証情報(IAMユーザなど)を使ってTerraformを実行することになるので、Terraform実行者の権限によっては、権限不足でTerraform実行が失敗する可能性があり、複数人で開発する場合、少し不便なことがあります。

これに対処する方法の一つが、Assume Roleを使ったTerraform実行です。
providerは以下のような設定になります。

provider "aws" {
  region = "ap-northeast-1"
  assume_role {
    role_arn = "arn:aws:iam::${var.aws_account_id}:role/TerraformExecutionInfraRole"
}

この設定だと、assume_roleで指定したTerraform実行用のロールの認証情報を使ってTerraformを実行することになるので、Terraform実行者の権限によって、権限不足でTerraform実行が失敗することは無くなります。
※勿論、Terraform実行ロールにassume roleする為の権限は、ローカルの認証情報に必要

Terraformで操作できる範囲を一元管理することもできますし、readonly + assume roleの権限のみ付与して、コンソールからはWrite不可、TerraformからはWrite可のような運用も可能です。

Assume Roleを使ったTerraform実行は、AWSのTerraformベストプラクティスでも推奨されています。

ただ、これには一点問題があります。
Assume Roleに詳しい方ならお気づきかと思いますが、誰がTerraformを実行しても、AWSを操作するのはTerraform実行用のロールなので、CloudTrailのイベント上、誰がTerraformを介してリソースを操作したのかが分からなくなってしまい、監査上少々問題があります。

この問題に対処する方法を本記事では紹介します。

設定方法

まず、assume_roleを指定するproviderとは別に、assume_roleを指定しないprovider(ローカルの認証情報を使用するprovider)を設定します

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

assume_roleを指定するproviderをデフォルトとしたいので、適当なaliasを設定します。

このproviderを使用して、dataリソースである、aws_caller_identityを定義します。

data "aws_caller_identity" "not_assume_role" {
  provider = aws.not_assume_role
}

このdataリソースは、ローカルの認証情報を使用して呼ばれるので、stateにもローカルの認証情報が保存されます。

 terraform console
> data.aws_caller_identity.not_assume_role
{
  "account_id" = "XXXXXXXXXXXX"
  "arn" = "arn:aws:sts::XXXXXXXXXXXX:assumed-role/XXXXXXXXXXXX"
  "id" = "XXXXXXXXXXXX"
  "user_id" = "XXXXXXXXXXXXXXXXXXXXX:falcon@hoge.co.jp"
}

このdataリソースの中で、ユーザを一意に特定できる属性をassume_roleを指定するproviderのsession_nameに設定します。
今回の例だと、user_idが使えそうなので、以下のように設定します(:はsession_nameに設定できないので_に置き換え)。

provider "aws" {
  region = "ap-northeast-1"
  assume_role {
    role_arn     = "arn:aws:iam::${var.aws_account_id}:role/TerraformExecutionInfraRole"
    session_name = replace(data.aws_caller_identity.not_assume_role.user_id, ":", "_")
  }
}

これで、Assume Roleを使ったTerraform実行でも、CloudTrailのイベント上にユーザを一意に特定できる情報が記録され、誰がTerraformを介してリソースを操作したのかの特定が可能になります。

モザイクまみれで分かり辛いですが、principalIdとarnに付与されるサフィックスがaws-go-sdk-xxxからsession_nameに設定した文字列に変更されています。

Discussion