AWS IAMの権限を、広すぎる状態から用途ごとに整理していった話
AWS IAMの権限を、広すぎる状態から用途ごとに整理していった話
個人開発で DevOps ポートフォリオ「terraform-hannibal」を作っています。
terraform-hannibal:
https://github.com/kmryst/terraform-hannibal
このプロジェクトでは、AWS / Terraform / GitHub Actions を使って、インフラ構築だけでなく、CI/CD、IAM、監査ログ、セキュリティチェック、Issue / PR 運用まで含めたDevOps基盤を作っています。
今回のテーマは、AWS IAMの権限設計です。
TerraformでAWSリソースを作るには、当然ながらIAM権限が必要です。
ただ、最初から完璧な最小権限を設計できるわけではありません。
動かすために一時的に広めの権限を持たせる。
Terraform planやapplyで必要なAPIが足りず、AccessDeniedが出る。
そのたびに権限を追加していく。
気づくと、RoleやPolicyの責務が曖昧になり、権限が広くなっている。
個人開発であっても、この状態をそのままにしておくのはよくないと考えました。
そこで terraform-hannibal では、広くなっていたAWS IAMの権限を、用途ごとに整理していくことにしました。
「動くこと」と「安全に運用できること」は違う
IAM権限は、広くすれば動きやすくなります。
たとえば、`iam:*` や `Resource: "*"` のような広い権限を使えば、Terraform apply時のAccessDeniedは減ります。
短期的には、開発は進めやすくなります。
しかし、その状態は安全とは言えません。
どのRoleが何をするためのものなのか。
どのPolicyがどの責務を持っているのか。
どこまでが通常操作で、どこからが危険な操作なのか。
誤って強い権限を追加したときに、どこで止められるのか。
これらが曖昧なままだと、運用の見通しが悪くなります。
terraform-hannibalでは、「とりあえず動く状態」から一歩進めて、RoleとPolicyの責務を分け、必要な権限だけに近づけることを意識しました。
最初から完璧を目指さず、段階的に整理する
IAMの最小権限化は、一気にやろうとすると危険です。
権限を削りすぎると、Terraform applyが止まります。
日常的な確認作業ができなくなります。
ECS Exec、ログ確認、ECR push、Secrets参照など、普段使っている操作が突然できなくなることもあります。
そこで、いきなり本体Roleを変更するのではなく、candidate Roleを作って検証してから本体へ反映する方針を取りました。
本体Roleを直接壊さず、候補となるRole / Policy / Permission Boundaryを別リソースとして作る。
そのcandidate Roleで実際の操作を確認する。
ECS Exec、ログ確認、ECR push、Secrets参照など、必要な操作が通るか確認する。
問題がなければ本体Roleへ反映する。
この流れにすることで、日常運用を止めずに権限を絞ることができます。
Zennでも、このcandidate-firstの進め方を記事にしています。
https://zenn.dev/kmryst/articles/terraform-iam-candidate-first-strategy
Permission Boundaryで「上限」も意識する
IAMでは、Policyで許可する権限だけでなく、Permission Boundaryによる上限制御も重要です。
Permission Boundaryは、RoleやUserが最終的に使える権限の上限を決める仕組みです。
terraform-hannibalでは、開発用Roleに対してPermission Boundaryを付与し、仮にPolicy側で強い権限が混入しても、Boundaryを超えた操作はできないようにする考え方を取り入れています。
ここで重要なのは、Permission Boundaryを「なんとなく付ける」のではなく、どのRoleにどんな上限を持たせるべきかを考えることです。
通常の開発用Role。
foundation層を扱うRole。
PR plan用のRole。
deploy / destroy用のRole。
それぞれ用途が違うため、必要な権限も、許容できるリスクも違います。
IAM設計では、単にPolicyを書くのではなく、Roleの責務とBoundaryの意味を合わせて考える必要があると感じました。
Policyを責務ごとに分ける
最小権限化を進めると、Policyの中身は細かくなります。
最初は広いワイルドカードで済んでいたものを、必要なAction単位で列挙していく。
S3、DynamoDB、CloudTrail、Athena、IAM、OIDC、Terraform stateなど、必要な権限を整理していく。
すると、1つのmanaged policyがどんどん大きくなります。
terraform-hannibalでは、IAM managed policyがAWSの文字数上限に近づいたため、責務ごとに3分割しました。
たとえば、foundation層を扱うRoleに付与するPolicyでも、すべてを1つに詰め込むのではなく、責務ごとに分けることで、何のための権限なのかを追いやすくしました。
Policyを分けると、管理対象は増えます。
一方で、責務が明確になり、レビューしやすくなります。
「この権限はstate管理のため」
「これはIAM / OIDC / Boundaryを扱うため」
「これは監査ログ基盤を扱うため」
というように、後から見たときに判断しやすくなります。
このPolicy分割についても、Zennに実装記録をまとめています。
https://zenn.dev/kmryst/articles/terraform-iam-managed-policy-split
Terraform管理では、権限変更そのものにも注意が必要
IAMをTerraformで管理する場合、権限を変えるだけでも注意が必要です。
たとえば、Policyを分割するときに、古いPolicyから権限を外す前に、新しいPolicyをRoleへattachしておく必要があります。
順番を間違えると、apply中にRoleが一時的に必要な権限を失う可能性があります。
また、Terraformリソースの中には、description変更がForceNewになり、delete + createになってしまうものもあります。
意図としては説明文を変えただけでも、実際にはリソースの再作成が発生することがあります。
IAMまわりでは、このような差分が特に危険です。
権限変更は「PolicyのJSONを少し直すだけ」に見えます。
しかし実際には、Roleのattach順序、Boundary、Terraform state、ForceNew、既存運用への影響まで考える必要があります。
この経験から、IAM設計ではplanを読む力と、差分の意味を解釈する力が重要だと感じました。
AccessDeniedは失敗ではなく、権限設計を詰める材料
TerraformやAWS CLIを使っていると、AccessDeniedに何度も遭遇します。
以前は、AccessDeniedが出ると「権限が足りないから追加する」と考えがちでした。
しかし、最小権限を意識すると、AccessDeniedは単なるエラーではなく、設計を詰める材料になります。
本当にそのActionが必要なのか。
Read権限だけでよいのか、Write権限が必要なのか。
Resourceを限定できるのか。
Roleを分けるべきなのか。
Policyに入れるべきか、Boundaryに入れるべきか。
こうした判断を積み重ねることで、権限設計が少しずつ整理されていきます。
terraform-hannibalでは、PR plan用RoleのS3 AccessDeniedをきっかけに、Terraform planがrefresh時に必要とするRead権限を見直したこともあります。
このようなエラー対応も、単なる場当たり的な修正ではなく、Roleの責務や権限境界を整理する機会として扱うようにしています。
個人開発だからこそ、権限設計を雑にしない
個人開発では、すべてを自分で操作できます。
レビューする人も少なく、多少権限が広くても作業は進みます。
だからこそ、意識しないと権限設計は雑になりやすいです。
しかし、DevOpsやインフラ運用では、権限設計は非常に重要です。
誰が何をできるのか。
どの操作は通常作業なのか。
どの操作は危険なのか。
どのRoleがどの責務を持つのか。
問題が起きたときに、どこまで影響を閉じ込められるのか。
これらを考えずに自動化だけ進めると、便利だけれど危険な基盤になります。
terraform-hannibalでは、個人開発でありながら、実務のチーム運用を想定して、IAM Role / Policy / Permission Boundaryを整理しています。
技術的な詳細
今回の権限整理に関係する内容は、Zennに複数の記事としてまとめています。
AWS IAMを「広すぎる権限」から最小権限に絞った話:
https://zenn.dev/kmryst/articles/aws-iam-least-privilege-portfolio-journey
本番IAMロールを壊さずに、candidate Roleで検証してから最小権限化した話:
https://zenn.dev/kmryst/articles/terraform-iam-candidate-first-strategy
IAM managed policyが文字数上限に近づいたため、Terraformで3分割した話:
https://zenn.dev/kmryst/articles/terraform-iam-managed-policy-split
terraform planのS3 AccessDeniedをIAMで解消した話:
https://zenn.dev/kmryst/articles/iam-pr-plan-s3-read-wildcard
これらの記事では、IAMの最小権限化、Permission Boundary、candidate Role、Policy分割、Terraform apply時の注意点などを整理しています。
今後の方向性
今後も terraform-hannibal では、AWS IAMの権限を「動けばよい」ではなく、「安全に運用できるか」という観点で見直していきたいと考えています。
最小権限を追いすぎると運用が重くなることがあります。
一方で、広すぎる権限のままではリスクが大きくなります。
その間で、どこまで権限を絞るか。
どこでPermission Boundaryによる上限を設けるか。
どのRoleにどの責務を持たせるか。
どの差分はすぐ反映し、どの差分はcandidateで検証してから反映するか。
こうした判断を積み重ねながら、AWS IAM、Terraform、CI/CDを安全に運用できるDevOps基盤として育てていきたいです。
インフラを作るだけでなく、権限を設計し、変更をレビューし、失敗時の影響範囲を小さくすること。
そうしたDevOps / SRE / Platform Engineering領域で価値を出せるエンジニアを目指しています。