メインコンテンツまでスキップ

IAM: ポリシー JSON の文法と Terraform 実行権限の現実解

第 1 章では、IAM を「誰が、何に対して、どの操作をできるか」を定義するサービスと位置づけました。権限の絞り方は本章に持ち越すと述べています1。ここまでの 2 章では、その約束を後回しにしたまま Terraform を動かしてきました。使っている AWS の認証情報は、管理者相当の強い権限を持ったままです2

権限を絞るには、まず AWS がその権限をどう表現し、どう評価しているかを知る必要があります。ポリシーという JSON ドキュメントの文法と評価順序、そしてロールという「引き受けて使う」身分の仕組みを見たうえで、Terraform 自身の認証情報をどこまで絞るかという、この連載自身の現実的な落としどころを決めます。

この章で学ぶポリシー JSON の読み方は、以降のすべての章に登場します。

3.1. IAM の基本要素

AWS へのリクエストは、まずプリンシパル (リクエストを送る実体そのもの。IAM ユーザーやロール、AWS のサービスなど) が何者であるかを確かめる認証を経ます。認証を通ったリクエストが実際に許可されるかどうかは、続く認可の判定に委ねられます3。第 1 章で「誰が、何に対して、どの操作をできるか」と述べたのは、この認証 (誰が) と認可 (何ができるか) の二段構えを指しています1

認可を決めるのは、プリンシパルに紐づいたポリシーです。ポリシーは JSON 形式のドキュメントで、何を (Action)、どのリソースに対して (Resource)、許可するか拒否するか (Effect) を記述します。

3.2. ポリシー JSON の文法

AWS の管理ポリシーの 1 つ、PowerUserAccess の一部を例に、ポリシー JSON の要素を見ます4

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"NotAction": ["iam:*", "organizations:*", "account:*"],
"Resource": "*"
}
]
}

PowerUserAccess の実物はこのあとに個別の許可を追加するステートメントが続きますが、文法の説明にはここまでで十分です。3.7 節では、このポリシーをそのままグループにアタッチして使います。

  • Version: ポリシー言語のバージョンを示す固定値です。上の例のように、現在の公式サンプルは "2012-10-17" を使っています4
  • Statement: 許可と拒否のルールを 1 個以上並べる配列です
  • Sid: ステートメントに任意で付けられる識別名です。複数のステートメントを並べたときに、どれが何のためかを示します (省略可)
  • Effect: そのステートメントが許可 (Allow) か拒否 (Deny) かを示します
  • Action: 対象となる API 操作です。iam:CreateUser のように <サービス>:<操作> の形を取ります
  • Resource: Action の対象になる AWS リソースを ARN (Amazon Resource Name) で指定します。すべてを対象にするときは "*" を使います
  • NotAction: Action の逆です。ここに挙げた操作以外のすべてに Effect を適用します。PowerUserAccess はこの NotAction で iam、organizations、account の 3 サービスを除外し、それ以外の全操作を許可するという書き方をしています

Resource は、どの Action でも自由に絞り込めるわけではありません。IAM のアクションによっては、その操作がどのリソースの単位にも紐づかず、Resource"*" を指定するしかない場合があります5。3.7 節で実際にポリシーを書くときに、この制約に触れます。

3.3. ポリシーの評価順序

1 つのプリンシパルに複数のポリシーがアタッチされていたとき、AWS はどんな順序でそれらを読むのでしょうか。単一の AWS アカウント内で、IAM ユーザーやロールに直接アタッチされたポリシー (identity-based policy) だけを考える限り、規則は次の 3 つに単純化できます6

  1. 既定はすべて拒否です。ポリシーが何もアタッチされていなければ、そのプリンシパルは何もできません (AWS アカウントの root ユーザーだけは既定で全許可という例外です)
  2. 明示的な Allow があれば、既定の拒否は上書きされます
  3. どこかのポリシーに明示的な Deny があれば、他にどれだけ Allow があってもその操作は拒否されます

3 つ目が、least privilege (3.5 節) の実務で効いてきます。ある操作を確実に禁止したいなら、単に許可を書かないのではなく明示的に Deny するステートメントを置くことで、他のポリシーがどんな Allow を持っていても上書きできます。

この 3 段階は、単一アカウント内の identity-based policy に限った単純化です。S3 バケットポリシーのようなリソースベースポリシーや、AWS Organizations の Service Control Policy が絡む場合、評価の順序はさらに複雑になります3。本連載は単一の AWS アカウントで完結するため、Service Control Policy は登場しません。一方で第 6 章では、ALB のアクセスログを受け取る S3 バケットにバケットポリシーを 1 つ書きます。そこで見るのは identity-based policy と resource-based policy の許可を足し合わせ、どちらかに明示的な deny があれば上書きされるという別の規則で、この章の 3 段階とは区別して扱います。

3.4. ロールと信頼ポリシー

IAM ユーザーは、特定の人やシステムに恒久的に紐づく身分で、認証には長期の認証情報 (パスワードやアクセスキー) を使います。これに対してロールは、人や AWS のサービスが一時的に引き受けて使う身分です。ロール自体は長期の認証情報を持たず、引き受けた側に一時的な認証情報が発行されます7

第 8 章で ECS のタスクにロールを持たせるように、AWS のサービスもロールを引き受けられます。ここで新しい疑問が生まれます。ロールにアタッチしたポリシーが「このロールに何ができるか」を決めるなら、「誰がこのロールを引き受けられるか」は何が決めるのでしょうか。

その役割を持つのが信頼ポリシー (trust policy) です。信頼ポリシーはロールにひとつだけ紐づく特別なポリシーで、sts:AssumeRole という操作を誰に許可するかを記述します8

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "<AWS サービス名>.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

Principal に指定した相手だけが、このロールを引き受けられます。指定できるのは AWS のサービスだけでなく、IAM ユーザーや別の AWS アカウントも対象にできます。どのサービスプリンシパルを使うかはロールを引き受ける AWS サービスによって決まり、第 8 章で ECS 向けの具体的な値を見ます。

通常のポリシーが「このプリンシパルは何ができるか」(認可) を記述するのに対して、信頼ポリシーは「誰がこのロールになれるか」というロール自体への入り口を記述します。両者を混同すると、ロールにいくら強い権限を与えても信頼ポリシーが誰も通さない、という手詰まりに陥ります。

本連載で実際に作るロールは、次の 2 つを見込んでいます。

ロール用途作成権限追加
ECS タスク実行ロール (execution role)コンテナイメージの取得やログ出力など、コンテナを起動し運用するためのインフラ側の権限第 8 章第 10 章 (Secrets Manager からの読み取り)
ECS タスクロール (task role)アプリケーションのコードが S3 など AWS のサービスを呼び出すための、アプリ側の権限第 8 章第 10 章 (S3 添付バケットへのアクセス)

この章で作る terraform-executors グループとユーザーは、人間 (または CI) が引き受ける権限です。ここに挙げた 2 つのロールは、コンテナという AWS のリソース自身が引き受ける権限であり、両者は別物です。

3.5. 最小権限の考え方

least privilege (最小権限) とは、あるプリンシパルに、その役割が必要とする最小限の操作だけを許可する考え方です9。IAM ユーザーやロールは既定では何の権限も持たないため、最小権限を実現する作業は許可を足していく作業になります。

AWS が Terraform 利用者向けに示す指針も同じ方向を向いています。空のポリシーから始め、必要になったサービスとアクションをそのつど足していく。先に広く許可してあとから絞るのではなく、先に厳しく始めて必要な分だけ開いていく、という順序です10。広い許可から削る作業は「本当に使われていない権限はどれか」を後から洗い出す必要があり、狭い許可に足す作業より手間も見落としも大きくなります。

とはいえ、この連載のように 11 章を通じて新しいサービスを次々に足していく構成では、章が進むたびにポリシーを 1 アクションずつ手で拡張し続けるのは現実的ではありません。実務でこの隙間を埋めるのが、AWS CloudTrail のログです。IAM Access Analyzer は、実際の API 呼び出しの記録から、そのプリンシパルが本当に使ったアクションだけを集めたポリシーを自動生成できます9。最初から手で最小限を書き切るのではなく、広めに始めて実際の使用実績から絞り込む、という進め方です。

次節で、この連載が実際にどこまで絞るかを決めます。

3.6. Terraform 実行権限の現実解

第 1 章の前提では、読者はすでに管理者相当の権限で AWS を操作できるアカウントを持っています2。ここから、Terraform 専用の絞り込んだ認証情報に切り替えます。

人間のアクセスに関する現在の AWS の推奨は、IAM ユーザーではありません。人間が AWS にアクセスする際は、IAM Identity Center による一元管理と、それを通じた一時的な認証情報の利用が推奨されています7。IAM Identity Center は AWS Organizations が前提の機能に見えますが、Organizations を使わないスタンドアロンのアカウントでも有効化できます11

それでも本連載では IAM Identity Center を採用しません。SSO の設定は Terraform の外側にある AWS コンソール側の作業で、ネットワークもデータベースもまだない第 3 章の時点でその設定に紙面を割くと、この連載の軸である Terraform の実装から話がそれてしまいます。個人開発や小規模な立ち上げ期を想定する Tasuku の規模でも、選択肢として存在することは知っておく価値があります。

この章で作るのは、IAM ユーザー 1 つと、それが属するグループです。ユーザーに直接ポリシーを書くのではなくグループにポリシーをアタッチするのは、担当者が増えたときにユーザーごとの設定を繰り返さずに済むためです。

権限の範囲は、PowerUserAccess という AWS 管理ポリシーを土台にします。このポリシーは IAM、AWS Organizations、アカウント管理の 3 領域を除くほぼすべての操作を許可します4。AWS 自身、IAM Identity Center の設定文脈ではありますが、通常の開発作業には AdministratorAccess でなく PowerUserAccess を勧めています12。ポリシーの中身は、IAM グループへ直接アタッチする場合と変わりません。

PowerUserAccess を土台に選ぶ理由は消去法です。この連載が触るサービス (VPC、S3、ALB、ECS、RDS、Route 53、ACM、Budgets) を 1 つずつ拾って最小限のアクションを書き下すと、11 章分の変更を通じてそのポリシーを常にメンテナンスし続けることになります。3.5 節で見た「まず広く始めて実績で絞る」進め方を、ここでは PowerUserAccess という既製の広さを借りることで代替します。

ただし PowerUserAccess には空白があります。IAM 自体の管理が対象外なのです。この章で作るグループやポリシー自体、そして第 8 章のロールも Terraform に作らせるため、IAM の操作をいくらか自分自身に許可し直す必要があります。

この補いは、書き込み系の操作と読み取り系の操作で扱いを変えます。グループやポリシー、ロール、ユーザーを作ったり変更したりする操作は、この連載のリソースだけに絞れます。IAM の各リソースには path という引数があり、ここに /tasuku/ のような接頭辞を付けると、ARN にもその接頭辞が入ります。この接頭辞を条件にすれば、書き込み系の許可を「tasuku 関連の IAM リソースだけ」に絞り込めます。

ここには注意点があります。この補助ポリシー自身も /tasuku/ 配下に置くため、書き込み系の許可はこのポリシー自身にも及びます。ポリシーの中身を書き換える iam:CreatePolicyVersion や、書き換えたバージョンを有効にする iam:SetDefaultPolicyVersion を許可すると、terraform-executors 自身が自分の権限を書き換えられてしまいます。この章の補助ポリシーは、この 2 つを含めないことでこの経路を塞いでいます13

もう 1 つ、iam:AttachGroupPolicy にも同種の抜け道があります。Resource をグループの ARN だけで絞っても、そのグループにどのポリシーを attach できるかは制限されません。放っておくと、AdministratorAccess のような AWS 管理ポリシーを terraform-executors グループへ直接 attach するだけで、結局フル権限に手が届いてしまいます。これを防ぐには、attach できるポリシー自体を条件で絞る iam:PolicyARN という条件キーが要ります14。3.7 節のコードでは AttachGroupPolicyAttachRolePolicy を別ステートメントに切り出し、この条件キーで /tasuku/ 配下のポリシーしか attach できないようにしています。

ここまでで代表的な 2 つの経路を塞ぎましたが、これで IAM の自己昇格経路を網羅したとは言い切れません。IAM には他にも複数の昇格パターンが知られており、自分自身の IAM リソースを操作できる権限を持つ限り、経路を 1 つずつ塞ぐやり方には限界があります。これを構造的に防ぐ本来の対策は、identity-based policy が付与できる権限の上限を別の管理ポリシーで固定する permissions boundary です15。本連載では個人開発規模というスコープの範囲で、見つかった経路への対処にとどめ、permissions boundary の導入は対象外とします。

一方、状態を読み取るだけの Get* 系や List* 系のアクションの多くは、そもそも特定のリソースに絞り込む仕組みを持たず、Resource"*" を指定するしかありません5。読み取りだけであれば絞り込めないことによる実害は書き込みほど大きくないため、ここは "*" のまま許可します。

最後に、意図的に作らないものがあります。IAM ユーザーのアクセスキーです。Terraform でアクセスキーを発行する aws_iam_access_key というリソースも存在しますが、これは使いません。Terraform の state ファイルは既定でローカルの JSON ファイルであり、機密情報を平文で保存してしまうことがあります16。AWS 自身、Terraform の state に秘密情報を平文で残すリソースは多く、可能な限り避けるべきだと述べています10。アクセスキーの発行は、AWS コンソールか AWS CLI から手動で行います。

3.7. terraform-executors グループを作る

iam.tf に、ここまでの設計を反映します。まずグループと、PowerUserAccess のアタッチです。

resource "aws_iam_group" "terraform_executors" {
name = "${local.name_prefix}-terraform-executors"
path = "/${var.project}/"
}

# PowerUserAccess は iam:* / organizations:* / account:* を除く全アクションを許可する
# AWS 管理ポリシー。この連載が触るサービスの大半はこれ1枚で足りる
resource "aws_iam_group_policy_attachment" "terraform_executors_power_user" {
group = aws_iam_group.terraform_executors.name
policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}

path = "/${var.project}/" が、3.6 節で触れた ARN の接頭辞です。policy_arn に指定した arn:aws:iam::aws:policy/PowerUserAccess は、AWS 管理ポリシーの ARN に共通する形式で、アカウント部分が固定文字列 aws になります17

次に、PowerUserAccess が除外する IAM 操作を補うポリシーです。ポリシー本体は jsonencode() で組み立てます。Terraform の値を JSON 文字列に変換する関数で、aws_iam_policy の公式ドキュメントもこの用途での利用を推奨しています18

resource "aws_iam_policy" "terraform_iam_management" {
name = "${local.name_prefix}-terraform-iam-management"
path = "/${var.project}/"
description = "PowerUserAccess が除外する IAM 操作のうち、この連載で Terraform 自身が必要とする分だけを補う"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "ManageProjectScopedIamWrite"
Effect = "Allow"
Action = [
"iam:CreateGroup",
"iam:DeleteGroup",
"iam:CreatePolicy",
"iam:DeletePolicy",
"iam:DetachGroupPolicy",
"iam:CreateUser",
"iam:DeleteUser",
"iam:AddUserToGroup",
"iam:RemoveUserFromGroup",
"iam:CreateRole",
"iam:DeleteRole",
"iam:UpdateAssumeRolePolicy",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:PassRole",
"iam:TagGroup",
"iam:TagPolicy",
"iam:TagRole",
"iam:TagUser",
]
# tasuku- が作る group/policy/role/user だけに書き込み権限を絞る
Resource = [
"arn:aws:iam::*:group/${var.project}/*",
"arn:aws:iam::*:policy/${var.project}/*",
"arn:aws:iam::*:role/${var.project}/*",
"arn:aws:iam::*:user/${var.project}/*",
]
},
{
# group/role の Resource だけでは attach 可能なポリシーの種類を制限できないため
# (AdministratorAccess 等の attach も通ってしまう)、iam:PolicyARN 条件で
# attach 可能なポリシー自体も /tasuku/ 配下に限定する
Sid = "AttachProjectScopedPoliciesOnly"
Effect = "Allow"
Action = [
"iam:AttachGroupPolicy",
"iam:AttachRolePolicy",
]
Resource = [
"arn:aws:iam::*:group/${var.project}/*",
"arn:aws:iam::*:role/${var.project}/*",
]
Condition = {
ArnLike = {
"iam:PolicyARN" = "arn:aws:iam::*:policy/${var.project}/*"
}
}
},
{
# Get/List は多くがリソースレベル権限に対応せず Resource "*" を要求する
# 読み取りのみなので影響範囲は限定的
Sid = "ReadIamForPlanning"
Effect = "Allow"
Action = [
"iam:Get*",
"iam:List*",
]
Resource = "*"
},
]
})
}

resource "aws_iam_group_policy_attachment" "terraform_executors_iam_management" {
group = aws_iam_group.terraform_executors.name
policy_arn = aws_iam_policy.terraform_iam_management.arn
}

iam:PassRole を最初のステートメントに含めているのは、第 8 章以降で ECS にロールを渡す (pass する) 操作も、同じ /tasuku/ 配下のロールに絞り込んでおきたいからです。AttachGroupPolicyAttachRolePolicy を別ステートメントに分けたのは、この 2 つだけ iam:PolicyARN という追加の条件キーを使うためです。ConditionArnLike は、iam:PolicyARN (attach しようとしているポリシー自体の ARN) が /tasuku/ 配下のパターンに一致する場合だけ許可を成立させます14

最後に、この権限一式を実際に使うユーザーです。

# root/管理者相当の認証情報から切り替える先の、絞り込み済み ID
resource "aws_iam_user" "terraform_executor" {
name = "${local.name_prefix}-terraform"
path = "/${var.project}/"
}

resource "aws_iam_user_group_membership" "terraform_executor" {
user = aws_iam_user.terraform_executor.name

groups = [
aws_iam_group.terraform_executors.name,
]
}

グループへのユーザー追加に aws_iam_group_membership ではなく aws_iam_user_group_membership を使っているのは、後者がユーザー起点の加算的な追加であるのに対し、前者はグループの所属ユーザー一覧を排他的に管理するためです19。今は 1 人しかいなくても、この先ユーザーが増えたときに、この 1 行が既存の所属を巻き込んで壊すことはありません。

最後に、実行者が絞り込み済みユーザーに切り替わっているかどうかを、planapply のたびに教えてくれる仕組みを 1 つ足します。

data "aws_caller_identity" "current" {}

# 実行者が絞り込み済みユーザーに切り替わっているかを毎 plan/apply で警告する
# (このリソース自体を作る最初の apply だけは admin 相当のままで警告が出るのが正しい)
check "terraform_caller_is_scoped_user" {
assert {
condition = data.aws_caller_identity.current.arn == aws_iam_user.terraform_executor.arn
error_message = "現在の実行者が ${aws_iam_user.terraform_executor.name} ではありません。管理者相当の認証情報のままになっていないか確認してください。"
}
}

check ブロックは、条件を満たさなくても planapply 自体は止めず、警告だけを出します20。この章の aws_iam_user を初めて作る apply では、実行者はまだ管理者相当の認証情報のままなので、この警告が出るのが正しい状態です。次の章から、実行者がこのユーザーに切り替わっていなければ警告が出続け、切り替え忘れに気づけます。

3.8. 動作確認

ここまでの iam.tf を、この連載でこれまでに書いた .tf ファイルと同じディレクトリに置いたら、次の順で確認します。

terraform fmt -check -recursive -diff
terraform init
terraform validate
terraform plan

plan を実行すると、次の 6 件の追加が計画に表示されるはずです。

  • aws_iam_group 1 件
  • aws_iam_policy 1 件
  • aws_iam_group_policy_attachment 2 件
  • aws_iam_user 1 件
  • aws_iam_user_group_membership 1 件

この 6 件とは別に、terraform_caller_is_scoped_user の警告が表示されます。この時点では実行者がまだ管理者相当の認証情報のままなので、想定どおりの警告です。

apply のあと、AWS コンソールか AWS CLI から、作成された IAM ユーザーのアクセスキーを発行してください。発行したキーを AWS CLI の新しいプロファイルに設定し、aws sts get-caller-identity の結果がこの章で作った IAM ユーザーの ARN になっていることを確認してから、次の章以降の apply はこのプロファイルで行います。root や管理者相当の認証情報は、この切り替えのあとは通常の作業から退けます。切り替えたあとに terraform plan を実行し直すと、terraform_caller_is_scoped_user の警告が消えることも確認してください。

本章のまとめ

  • IAM のリクエスト処理は認証 (誰か) と認可 (何ができるか) の二段構えで、認可を決めるのがポリシーという JSON ドキュメントです
  • ポリシーの評価は、単一アカウント内の identity-based policy に限れば「既定拒否 → 明示的 allow で上書き → 明示的 deny が常に優先」の 3 段階に単純化できます
  • ロールは一時的に引き受ける身分で、信頼ポリシーが「誰が引き受けられるか」を、通常のポリシーが「引き受けた先で何ができるか」を分担します
  • 最小権限は許可を少しずつ足す考え方ですが、この連載では PowerUserAccess を土台に IAM 操作だけを補うことで、11 章分のメンテナンスコストと折り合いをつけました
  • Terraform 実行専用の IAM ユーザーとグループを作り、アクセスキーは state ファイルへの露出を避けるため手動で発行します

次に読む

Footnotes

  1. 出典: 第 1 章 1.5 節。「誰が、何に対して、どの操作をできるか」の認証と認可を定義するサービスとして IAM を紹介しています。 2

  2. 出典: 第 1 章 1.7 節。「管理者相当の権限で操作できるアカウント」を前提とし、権限の絞り方は第 3 章で扱うと予告しています。 2

  3. 出典: Policy evaluation logic。リクエストの処理は認証、適用ポリシーの特定、許可可否の判定という 3 段階からなり、identity-based policy 以外にも resource-based policy や AWS Organizations の SCP/RCP が絡むケースを扱っています。 2

  4. 出典: AWS 管理ポリシー PowerUserAccess 2 3

  5. 出典: Actions, resources, and condition keys for AWS services。アクションによってはリソースレベル権限に対応せず、Resource"*" を指定するしかない場合があるとしています。 2

  6. 出典: How AWS enforcement code logic evaluates requests to allow or deny access。既定は暗黙的拒否、明示的な allow が必要、明示的な deny が allow を上書きするという評価順序を示しています。

  7. 出典: Security best practices in IAM。人間のアクセスには一時的な認証情報の利用と、一元管理のための IAM Identity Center を推奨しています。 2

  8. 出典: Resource: aws_iam_roleassume_role_policy の例として、sts:AssumeRole を許可する信頼ポリシーの構造を示しています。

  9. 出典: SEC03-BP02 Grant least privilege access。最小権限の定義と、AWS CloudTrail のログと IAM Access Analyzer による実績ベースのポリシー生成を扱っています。 2

  10. 出典: Security best practices (Terraform AWS Provider)。空のポリシーから段階的に許可を足す進め方と、state に秘密情報を平文で残すリスクの両方に触れています。 2

  11. 出典: Organization and account instances of IAM Identity Center。AWS Organizations を使わないスタンドアロンアカウントでも account instance を有効化できるとしています。

  12. 出典: Using IAM Identity Center to authenticate AWS SDK and tools。通常の開発作業には AdministratorAccess でなく PowerUserAccess を使うよう推奨しています。

  13. 出典: Versioning IAM policiesiam:CreatePolicyVersioniam:SetDefaultPolicyVersion のどちらか一方でも許可されていれば、既存ポリシーの中身を書き換えて有効化できるとしています。

  14. 出典: Control access to AWS resources using policiesiam:AttachGroupPolicyiam:AttachRolePolicyResource をグループやロールの ARN で絞っても attach 可能なポリシーの種類は制限されず、iam:PolicyARN 条件キーで別途絞り込む必要があるとしています。 2

  15. 出典: SEC03-BP02 Grant least privilege access。permissions boundary は identity-based policy が付与できる権限の上限を設定する仕組みで、実際に許可される操作は両者の積集合になるとしています。

  16. 出典: Using Secrets Manager and Terraform。Terraform の state は既定でローカルの JSON ファイルであり、機密データを平文で保存しうるとしています。

  17. 出典: Using IAM in the AWS CLIPowerUserAccess の ARN が arn:aws:iam::aws:policy/PowerUserAccess であることを CLI の実行例で示しています。

  18. 出典: Resource: aws_iam_policypolicy の組み立てに jsonencode() の利用を推奨しています。

  19. 出典: Resource: aws_iam_user_group_membership。ユーザー起点で他のグループ所属と衝突しない加算的な管理をするとし、グループ起点で所属を排他的に管理する aws_iam_group_membership と使い分けるよう案内しています。

  20. 出典: check block referencecheck ブロックのアサーションが失敗しても planapply は停止せず、警告を報告して処理を続けるとしています。Terraform 1.5 で導入された機能です。