AWSの学び直しをIAMから始めることにしました。EC2でもS3でもなくIAMが最初なのは、どのサービスを触るにしても真っ先にぶつかるのが権限の壁だからです。aws s3 lsを打ってAccessDeniedが返ってきたら、調べる先は結局IAMになります。
ただ、IAMは用語が紛らわしいです。ユーザー、グループ、ロール、ポリシー。どれも「権限に関わる何か」なのは分かるものの、役割の線引きが最初は見えません。検索サジェストでも「iam ロール ポリシー 違い」「iam ユーザー ロール 違い」がよく出てくるので、同じところで引っかかる人は多いようです。公式ドキュメントを読み込みながら、この4つの関係を後から読み返せる形でまとめました。
前提は、AWSアカウントとマネジメントコンソールに入れる環境だけです。IAMの利用自体は無料で、動作確認も課金の発生しないポリシーシミュレーターの範囲にとどめています。
登場人物は4つ、ただし並列ではない
ユーザー・グループ・ロール・ポリシーを対等な4兄弟として覚えようとすると混乱します。整理の手がかりは公式ドキュメントの章立てにありました。「IAM アイデンティティ」という章に載っているのはユーザー・ユーザーグループ・ロールの3つだけで、ポリシーは「AWS Identity and Access Management でのポリシーとアクセス許可」という別の章で扱われています。つまりアイデンティティが3種類あり、ポリシーはそれらに与える権限の定義書、という非対称な構図です。
アイデンティティ3つ+定義書1つという構図
それぞれの役割を一言でまとめると次の通りです。
- ユーザー: 1人の人間、または1つのアプリケーションに対応するアイデンティティ。パスワードやアクセスキーといった長期的な認証情報を持つ
- ユーザーグループ: ユーザーをまとめる箱。グループにポリシーをアタッチすると、所属ユーザー全員に権限が行き渡る
- ロール: 特定の誰かに紐づかないアイデンティティ。EC2やLambda、他アカウントのユーザーなどが「引き受けて」使う
- ポリシー: 何を許可(拒否)するかを定義するJSON文書。単体では何も起こせず、アイデンティティにアタッチして初めて効く
基本の関係は「アイデンティティにポリシーをアタッチする」の一方向だけです。ポリシー側にユーザーを登録するのではなく、ユーザー(やグループ、ロール)の側にポリシーを付けます。
ルートユーザーだけは別枠
紛らわしい存在としてルートユーザーがあります。アカウント作成時に自動的に作られ、すべてのAWSサービスとリソースにアクセスできる特別なプリンシパルで、IAMユーザーとは別物です。ポリシーで権限を絞る対象として扱えないため、ルートユーザーは初期設定などごく一部の作業に限定し、MFAを有効化したうえで日常の操作はIAMユーザー(または IAM Identity Center)側で行うのが公式の推奨です。
ポリシー—権限を定義するJSON文書
4要素の中で唯一の「定義書」であるポリシーから押さえます。中身はただのJSONです。
Effect・Action・Resourceの3点セット
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadAppLogs",
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetObject"],
"Resource": [
"arn:aws:s3:::my-app-logs",
"arn:aws:s3:::my-app-logs/*"
]
}
]
}
読み方はシンプルで、Effectが許可(Allow)か拒否(Deny)か、Actionが「サービス名:操作名」形式の対象操作、ResourceがARNで指定する対象リソースです。これをカスタマー管理ポリシーとして登録すると、アカウント内でARNが割り当てられます。
aws iam create-policy \
--policy-name s3-app-logs-readonly \
--policy-document file://policy.json
{
"Policy": {
"PolicyName": "s3-app-logs-readonly",
"Arn": "arn:aws:iam::123456789012:policy/s3-app-logs-readonly",
"DefaultVersionId": "v1",
"AttachmentCount": 0,
"CreateDate": "2026-08-15T02:14:37+00:00"
}
}
ポリシーに書かれていない操作は暗黙的に拒否され、明示的なDenyはAllowより常に優先されます。この評価順序は奥が深いので、別記事で掘り下げる予定です。
Versionの日付は「今日の日付」ではない
見落としやすいのがVersionフィールドです。これはポリシーを書いた日付ではなくポリシー言語仕様のバージョンで、公式ドキュメントによると最新版は2012-10-17。10年以上前の日付ですが、常にこの値を書きます。省略すると古い仕様(2008-10-17)として解釈されてポリシー変数などが使えなくなるため、機械的に付けておくのが安全です。
管理ポリシーとインラインポリシー
ポリシーには「置き場所」による区別もあります。公式の分類は次の3つです。
| AWS管理ポリシー | カスタマー管理ポリシー | インラインポリシー | |
|---|---|---|---|
| 作成・管理 | AWS | 自分のアカウント | 自分のアカウント |
| 複数のIDへの再利用 | できる | できる | できない(1つのIDに埋め込み) |
| 内容の編集 | できない | できる | できる |
| 例・特徴 | ReadOnlyAccessなど | 要件に合わせて絞れる | IDを削除すると一緒に消える |
インラインポリシーは単一のユーザー・グループ・ロールに直接埋め込む形式で、親のIDを削除すると自動的に削除されます。公式ドキュメントは、ポリシーとIDの厳密な1対1関係を保ちたい場合を除いて管理ポリシーの利用を勧めています。基礎固めの段階では、まずReadOnlyAccessのようなAWS管理ポリシーで動きを確かめ、絞りたくなったらカスタマー管理ポリシーを作る流れが分かりやすいと思います。
ユーザーとグループ—人に権限を届ける経路
ユーザー直付けをやめてグループ経由にする
やりがちなのが、メンバー一人ひとりにポリシーを直接アタッチしていくパターンです。
# NG: 人数分これを繰り返すことになる
aws iam attach-user-policy --user-name dev-sato \
--policy-arn arn:aws:iam::123456789012:policy/s3-app-logs-readonly
aws iam attach-user-policy --user-name dev-suzuki \
--policy-arn arn:aws:iam::123456789012:policy/s3-app-logs-readonly
2〜3人なら回りますが、「開発者の権限を1つ増やす」たびに全員分の操作が必要になり、いずれ抜け漏れが出ます。グループにポリシーをアタッチしてユーザーを所属させる形なら、権限の変更はグループ1箇所で済みます。
aws iam create-group --group-name developers
aws iam attach-group-policy --group-name developers \
--policy-arn arn:aws:iam::123456789012:policy/s3-app-logs-readonly
aws iam add-user-to-group --group-name developers --user-name dev-sato
aws iam list-groups-for-user --user-name dev-sato
{
"Groups": [
{
"GroupName": "developers",
"GroupId": "AGPAJ2EXAMPLE3EXAMPLE",
"Arn": "arn:aws:iam::123456789012:group/developers",
"CreateDate": "2026-08-15T02:31:09+00:00"
}
]
}
グループは入れ子にできない
グループを設計するときに効いてくる制約が、公式ドキュメント「IAM ユーザーグループ」に明記されています。
ユーザーグループを入れ子形式にすることはできません。ユーザーグループにはユーザーのみを含めることができ、他の IAM グループを含めることはできません。
「developersの中にbackendチーム」のような階層は組めないということです。代わりにユーザーは複数のグループに所属できるので、developersとbackendの両方に入れる、というフラットな設計になります。またグループはあくまでユーザーをまとめる箱で、グループとしてログインしたり、ロールのようにAWSサービスへ権限を渡したりはできません。
ロール—誰にも属さないアイデンティティ
初見で一番つかみにくいのがロールだと思います。公式ドキュメント「IAM アイデンティティ」では、ロールを「特定の許可を持つアイデンティティで、IAMユーザーに似ているものの特定の1人には関連付けられていない」ものと説明しています。この「誰にも属さない」が核心です。
パスワードも永続アクセスキーも持たない
ユーザーとの最大の違いは認証情報の持ち方です。ユーザーはパスワードやアクセスキーという長期的な認証情報を持ちますが、ロールは持ちません。ロールは誰かが「引き受ける(assume)」もので、引き受けた瞬間に有効期限付きの一時的な認証情報が発行されます。アクセスキーをサーバーに置きっぱなしにして漏洩する、という事故をそもそも起こさないための、「認証情報を配らずに権限だけ渡す」仕組みと捉えると分かりやすいです。
信頼ポリシーと許可ポリシーの2枚構え
ロールにはポリシーが2種類関わります。何ができるかを決める許可ポリシー(ここまでに見てきた通常のポリシー)と、誰がこのロールを引き受けられるかを決める信頼ポリシーです。マネジメントコンソールでは「信頼関係」タブに表示されるので、サジェストに出てくる「iam ロール 信頼関係」はこれを指します。EC2に引き受けさせる場合の信頼ポリシーはこう書きます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
Principalという、通常のポリシーには書かない要素が出てきました。調べてみたら理由は明快で、公式の「ポリシーとアクセス許可」の章ではロールの信頼ポリシーはリソースベースのポリシーに分類されています。ロールというリソースの側に「誰からのアクセスを受け入れるか」を書くポリシーなので、主語(プリンシパル)の指定が必要になるわけです。アイデンティティベースのポリシーはアタッチ先自身が主語なので、Principalを書きません。
EC2がロールを引き受けると何が起きるか
このロールをEC2インスタンスに割り当てて(内部的にはインスタンスプロファイルという入れ物を経由します)、インスタンス上で自分が誰なのかを確認すると、ユーザーではなくロールとして動いていることが分かります。
aws sts get-caller-identity
{
"UserId": "AROAJ2EXAMPLE3EXAMPLE:i-0a1b2c3d4e5f67890",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/ec2-app-role/i-0a1b2c3d4e5f67890"
}
ARNがuser/ではなくassumed-role/で始まっているのがポイントです。同じ仕組みで、別のAWSアカウントのユーザーや、外部IDプロバイダーからフェデレーションしたIDにもロールを引き受けさせられます。公式ドキュメントにも、フェデレーションされたIDは「AWS リソースにアクセスするための IAM ロールを引き受ける」と書かれています。引き受けの実体であるAssumeRole APIとSTSは、学習順としてこの次の次に控えているテーマなので、そちらで掘り下げます。
「ロールとポリシーの違い」を一言で言うと
ポリシーは権限の中身、ロールは権限の器
ここまでを踏まえると、冒頭の紛らわしさは一文に集約できます。ポリシーは「何をしてよいか」の定義書で、ロールはユーザーやグループと同じく、その定義書をアタッチされる器です。ロール自体に権限の中身は書かれておらず、アタッチされた許可ポリシーが中身を決めます。「ロールを作ったのに何もできない」ときは、たいてい器だけ作って定義書を入れ忘れています。
ユーザーとロールの違いは「専属かどうか」
もう1つの混同ペアであるユーザーとロールは、専属か共用か、そして認証情報の持ち方で区別します。4要素を並べると次の通りです。
| ユーザー | グループ | ロール | ポリシー | |
|---|---|---|---|---|
| 正体 | 人・アプリ専属のアイデンティティ | ユーザーの集合 | 共用のアイデンティティ | 権限を定義するJSON文書 |
| 認証情報 | パスワード・アクセスキー(長期) | 持たない | 引き受け時の一時認証情報のみ | — |
| ポリシーのアタッチ | できる | できる | できる | —(自身が定義書) |
| 主な用途 | 個人のコンソール・CLI操作 | 人への権限の一括配布 | AWSサービス・他アカウント・フェデレーションへの権限付与 | 権限内容の定義 |
課金なしで検証する—IAMポリシーシミュレーター
simulate-principal-policyで机上検証
「このユーザーでこの操作は通るのか」を、実際のリソースに触らず確認できるのがIAMポリシーシミュレーターです。ブラウザ版(policysim.aws.amazon.com)もありますが、CLIのsimulate-principal-policyなら結果をそのまま記録に残せます。ポリシーの評価だけを行うのでリソースは作られず、料金もかかりません。
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/dev-sato \
--action-names s3:GetObject s3:PutObject \
--resource-arns arn:aws:s3:::my-app-logs/app.log
"EvaluationResults": [
{ "EvalActionName": "s3:GetObject", "EvalDecision": "allowed" },
{ "EvalActionName": "s3:PutObject", "EvalDecision": "implicitDeny" }
]
s3:PutObjectの結果はimplicitDeny、つまり「どのポリシーにも書かれていないので暗黙的に拒否」です。以前はテスト用ユーザーを作って実際にAPIを叩いては消していたので、シミュレーターを知ってから権限の切り分けがずいぶん楽になりました。明示的なDenyに当たった場合はexplicitDenyと区別して表示されます。この「拒否が許可に勝つ」評価の考え方はAWSに限った話ではなく、Claude Code permissions—allow/denyの落とし穴と評価順序で整理したpermissionsの評価順序ともよく似ています。
覚えておきたい上限(クォータ)
サジェストに「iam ロール 上限」と出てくる通り、上限も基礎知識として押さえておくと設計時に慌てません。公式の「IAM と AWS STS クォータ」から主なものを拾います。
- グループ数: アカウントあたりデフォルト300
- ロール数: アカウントあたりデフォルト1,000(引き上げ申請可)
- 1つのユーザー/ロールにアタッチできる管理ポリシー: デフォルト10個
- カスタマー管理ポリシーのサイズ: 6,144文字まで
個人の学習用途で困る数字ではないものの、「管理ポリシー10個」は権限を細かく分割しすぎると意外と早く到達します。ポリシーの粒度を考えるきっかけになる数字です。
まとめ
- IAMの4要素は並列ではなく、アイデンティティ3種(ユーザー・グループ・ロール)+権限の定義書(ポリシー)という構図で捉える
- ポリシーはEffect・Action・ResourceのJSON文書。
Version: 2012-10-17はポリシー言語のバージョンで固定値 - ユーザーへの直接アタッチは避けてグループ経由で配る。グループは入れ子にできない
- ロールは長期的な認証情報を持たない共用のアイデンティティ。信頼ポリシー(誰が引き受けるか)と許可ポリシー(何ができるか)の2枚構えで動く
- 信頼ポリシーはリソースベースのポリシーに分類される。
Principalを書くのはそのため - 権限の検証はIAMポリシーシミュレーターを使えば課金なしで完結する
次はポリシーが複数重なったときの評価順序と暗黙のDenyを掘り下げます。AssumeRoleによるサービス間の権限委譲も、このシリーズの続きとして扱う予定です。