プロジェクトで使用するIAMロール・ポリシー・ユーザー・グループをTerraformで一括管理する設計パターンを解説する。 マネージドポリシーとインラインポリシーの使い分け、AWSクォータを踏まえた設計判断を紹介する。
ページ構成
- IAM一括管理の動機と設計方針
- 管理対象
- ポリシー設計:マネージドポリシー vs インラインポリシーの使い分け
- IAMクォータ比較表
- IAMユーザー管理と認証情報の安全な格納
- まとめ
1. IAM一括管理の動機と設計方針
課題:IAMロールの散逸
プロジェクトが成長するにつれ、ECS、Lambda、CodeBuild、EC2など各サービスごとにIAMロールが必要になる。 これらを各リソース定義の近くに個別作成すると、以下の問題が生じる。
- ロールの全体像が見えない: どのロールが存在し、何の権限を持つか把握しづらい
- 命名規則の不統一: 作成者・タイミングによって命名がばらつく
- 権限の重複・過剰付与: 似たポリシーが複数箇所で定義され、棚卸しが困難
- 変更時の影響範囲が不明: ポリシー変更がどのサービスに影響するか追跡しにくい
設計方針:一箇所に集約
プロジェクトで使用するIAMロールを 一箇所のTerraformファイルに集約 する。
infrastructure/
└── environments/
└── prod/
└── iam.tf ← 全ロールを宣言的に定義
これにより得られるメリット:
- 一覧性: 1ファイルを見れば、環境内の全IAMロール・ポリシー・ユーザーが把握できる
- 命名の統一:
{prefix}-iam-{name}-{env}の命名規則を自動適用 - レビューの容易さ: IAM変更は必ずこのファイルに集約されるため、PRレビューで権限変更を見落としにくい
- 棚卸しの簡素化: Terraformのstateと宣言を突き合わせることで、不要ロールの検出が容易
2. 管理対象
一括管理の対象とするIAMリソースは以下の通り。
| リソース種別 | 説明 |
|---|---|
| IAM Role | サービスロール(ECS, Lambda, EC2, CodeBuild等) |
| IAM Policy | カスタムマネージドポリシー |
| IAM Role Policy Attachment | ロールへのポリシーアタッチ |
| IAM Instance Profile | EC2用インスタンスプロファイル |
| IAM User | プログラマティック/コンソールユーザー |
| IAM Group | ユーザーグループ |
ロール定義では、AssumeRoleを許可するサービスを宣言的に指定する。
| サービス | AssumeRole Principal | 用途 |
|---|---|---|
| ECS Task | ecs-tasks.amazonaws.com | ECSタスク実行 |
| Lambda | lambda.amazonaws.com | Lambda関数実行 |
| EC2 | ec2.amazonaws.com | EC2インスタンス |
| CodeBuild | codebuild.amazonaws.com | CodeBuildプロジェクト |
| EventBridge | events.amazonaws.com | EventBridgeルール |
| Scheduler | scheduler.amazonaws.com | EventBridge Scheduler |
AWS以外のPrincipal(クロスアカウントのIAMロール等)からのAssumeRoleが必要な場合は、カスタムのAssumeRoleステートメントで柔軟に対応する。
3. ポリシー設計:マネージドポリシー vs インラインポリシーの使い分け
基本方針
一括管理で アタッチするポリシーは汎用的なものだけ に限定する。
具体的には以下の2種類のみ:
- AWSマネージドポリシー(例:
AmazonECSTaskExecutionRolePolicy) - リソースが
*のカスタムポリシー(例:logs:CreateLogGroupに対してresource = ["*"])
なぜ汎用ポリシーだけなのか
IAMの一括管理はインフラの初期構築フェーズで適用される。この時点では、具体的なリソースARN(S3バケット名、RDSクラスターARN等)がまだ確定していない場合がある。
そのため:
- 汎用ポリシー → 一括管理で事前にアタッチ
- 限定的なアクセス許可(特定ARNへのアクセス等) → リソース作成時にインラインポリシーで追加
インラインポリシーによる詳細権限の追加
リソースを作成するタイミングで、そのリソースへのアクセス権をインラインポリシーとしてロールに追加する。
# S3バケット作成時に、ECSタスクロールへのアクセス権をインラインポリシーで付与
resource "aws_iam_role_policy" "ecs_task_s3_access" {
name = "s3-app-bucket-access"
role = module.iam.iam_roles["ecs_task"].name
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = ["${aws_s3_bucket.app.arn}/*"]
}
]
})
}
この方式のメリット:
- マネージドポリシーアタッチ数の上限を回避: マネージドポリシーのアタッチ上限に縛られず、詳細な権限を追加できる
- リソースとポリシーの近接性: 権限の定義がリソース定義の近くにあるため、「何のために」が明確
- 最小権限の実現: 具体的なARNを指定できるため、
resource = ["*"]を避けられる - ライフサイクルの一致: リソース削除時にインラインポリシーも自然に削除対象になる
4. IAMクォータ比較表
IAMロールに対するポリシーの上限値を以下に整理する。
| 項目 | デフォルト上限 | 最大(引き上げ後) | 備考 |
|---|---|---|---|
| マネージドポリシー(ロールあたり) | 10 | 25 | Service Quotasから引き上げ申請可能 |
| マネージドポリシー(ユーザーあたり) | 10 | 20 | Service Quotasから引き上げ申請可能 |
| マネージドポリシー(グループあたり) | 10 | 10 | 引き上げ不可 |
| インラインポリシー(ロールあたり) | 個数上限なし | - | 合計サイズ上限: 10,240文字 |
| インラインポリシー(ユーザーあたり) | 個数上限なし | - | 合計サイズ上限: 2,048文字 |
| インラインポリシー(グループあたり) | 個数上限なし | - | 合計サイズ上限: 5,120文字 |
| カスタムマネージドポリシー(アカウントあたり) | 1,500 | 10,000 | Service Quotasから引き上げ申請可能 |
インラインポリシーは個数の上限はないが、エンティティあたりの合計ポリシーサイズ(文字数)に上限がある。ホワイトスペースはカウントされない。
出典: IAM and AWS STS quotas - AWS Identity and Access Management
設計上のポイント
マネージドポリシーのアタッチ上限(デフォルト10、最大25)は、サービスが増えると容易に到達する。 一方、インラインポリシーは 個数制限がなく、合計サイズ(ロールの場合10,240文字) が上限となる。
この特性を活かし:
- 汎用的な権限 → マネージドポリシーとしてアタッチ(上限枠を消費するが、再利用性が高い)
- リソース固有の権限 → インラインポリシーで追加(上限枠を消費せず、詳細に設定可能)
という使い分けにより、マネージドポリシーの上限を超えて詳細な権限設定が可能になる。
5. IAMユーザー管理と認証情報の安全な格納
課題:認証情報の散逸
IAMユーザーを作成すると、認証情報(アクセスキーまたはパスワード)が生成される。 この認証情報をどこに保存するかが明確でないと、以下の問題が生じる。
- Terraformの出力やコンソール画面に平文で表示され、Slackやメールで共有される
- 保存先が担当者ごとにバラバラになり、棚卸し不能になる
- 「認証情報はどこにありますか?」という監査時の質問に即答できない
- 退職・異動時に、どの認証情報を無効化すべきか追跡できない
設計方針:作成と同時に安全な格納先へ自動振り分け
IAMユーザーの作成と同時に、認証情報を用途に応じた格納先に自動的に保存する。
terraform output に認証情報の平文は出力されず、格納先のARNまたはパス名だけが出力される。
認証タイプ別の動作
| 認証タイプ | 用途 | 生成されるもの | 格納先 | 取得方法 |
|---|---|---|---|---|
| アクセスキー | CI/CD、プログラマティックアクセス | Access Key ID + Secret Access Key | Secrets Manager | aws secretsmanager get-secret-value |
| コンソール | AWSマネジメントコンソールアクセス | 初回パスワード(変更必須) | SSM Parameter Store (SecureString) | aws ssm get-parameter --with-decryption |
6. まとめ
| 設計判断 | 内容 |
|---|---|
| ロールの集約管理 | 全IAMロールを1ファイルに集約し、一覧性とレビュー容易性を確保 |
| 汎用ポリシーのみ一括アタッチ | AWSマネージドポリシーまたは resource = ["*"] のポリシーのみを一括管理で設定 |
| 限定権限はインラインポリシー | リソース作成時にインラインポリシーで追加し、マネージドポリシー上限を回避 |
| 認証情報の安全な管理 | アクセスキーはSecrets Manager、コンソール認証情報はSSM Parameter Storeに自動格納 |
| 宣言的なAssumeRole | サービス名リストまたはカスタムステートメントで柔軟に対応 |