概要
AWSやGoogle Cloudを使用していると、IAMロールやIAMポリシーを過剰な権限で作成したりいつの間にか知らないIAMポリシーを放置してしまったりということが多くあると思います(特に開発環境ではとりあえず作って放置してしまいがちです)
今回はAWSに焦点を当てて不要なIAMを一覧化して整理の手助けできるようにできないかを検討してみたいと思います
本題
軽く考えたなかでのアプローチとしては
- IAM Access Analyzerを使って分析する
- CLIもしくはPythonを使って独自に取得処理を作成する
という2点が考えられました
CLIやPythonスクリプトについてはAPI調べて書けば良い話なので必要になったら解説しながら書きますが、まずは「IAM Access Analyzer」について軽く調べた内容を記したいと思います
IAM Access Analyzerとは
IAMを管理していく上でアクセス検知や使っていないIAMが存在すれば検知するなど、IAMに関して色々なことを行なってくれるサービスです
Geminiがまとめてくれた内容としては以下の内容となっています(内容的には大きく乖離は発生していないと思います)
| 機能 | 概要 | 使用目的 | 料金 |
|---|---|---|---|
| 外部アクセス検出 (External Access) | 組織外部(他のAWSアカウント、AWSのサービス外、パブリック)と共有されているリソースを検出します。 | 意図しないパブリックアクセスやクロスアカウントアクセスを防ぐ。 | 無料 |
| 未使用アクセス検出 (Unused Access) | 指定した追跡期間内に使用されていないIAMロール、IAMユーザーのアクセスキー、IAMユーザーのパスワード、およびポリシー内の権限を継続的に監視し、特定します。 | 権限の過剰付与(Permission Creep)を特定し、セキュリティリスクを軽減する。 | 有料 |
| ポリシー生成 (Policy Generation) | AWS CloudTrailのアクセスアクティビティに基づいて、必要なアクションのみを含むきめ細かなIAMポリシーを自動的に生成します。 | 新しいポリシーを作成する際、最小限の権限で始めるための強力な土台を作成する。 | 無料 |
| ポリシーチェック (Policy Validation) | IAMポリシーを作成または変更する際、セキュリティのベストプラクティス、文法、およびエラーをチェックします。 | デプロイ前の設定ミスによる過度な権限付与を未然に防ぐ。 | 無料 |
| カスタムポリシーチェック (Custom Policy Checks) | ポリシー変更が、事前に定義した企業のセキュリティ基準や特定の要件に違反していないかを検証します。 | 組織独自のセキュリティ基準をポリシーレビュープロセスに組み込む。 | 有料 |
今回やりたいこと的には「未使用アクセス検出」というのが適していそうだと思いました
ただ、ここで気になるところとしては有料というところかと思われます
実際に公式のドキュメントを確認すると以下のような料金形態となっております
ap-northeast-1での計算ですが、 1つのIAMロールまたはユーザーIAMにつき0.2USDだそうです
開発環境などで実行するとかなりの料金になる気がします
またIAMポリシーについては不要かどうかを判別する方法はなさそうでした
ということで手間ではありますがこういう小さなところから節約を積み重ねたり、コーディングについて考えられる機会だと思って次に進んでいきたいと思います
CLI or Pythonで処理を考える
Pythonまで手が回らず、とりあえずCLIベースのところが完成したので、そこを説明したいと思います
スクリプト本体は以下になります
別途インストールが必要なものはjqとaws-cliになります(別途調べていただければと思います)
#!/bin/sh
# 依存関係:
# 1. aws-cli (設定済みであること)
# 2. jq (JSONパーサー)
# jqがインストールされているかチェック
if ! command -v jq &> /dev/null; then
echo "エラー: このスクリプトの実行には 'jq' が必要です。" >&2
echo "インストールしてください (例: brew install jq, apt install jq, yum install jq)" >&2
exit 1
fi
# 出力ファイル名
OUTPUT_FILE="iam_policies_summary.tsv"
echo "policy_name\tversion_id\tused_as\tentities\tpolicy_detail" > "$OUTPUT_FILE"
aws iam list-policies --scope Local --output json | \
jq -c '.Policies[] | {name: .PolicyName, arn: .Arn}' | \
while read policy_line; do
policy_name=$(echo "$policy_line" | jq -r '.name')
arn=$(echo "$policy_line" | jq -r '.arn')
echo "処理中: $policy_name"
policy_details=$(aws iam get-policy --policy-arn "$arn" \
--query 'Policy.{Ver:DefaultVersionId, Count:AttachmentCount}' \
--output json 2>/dev/null)
if [ -z "$policy_details" ]; then
echo " -> エラー: ポリシー詳細(get-policy)を取得できませんでした。スキップします。" >&2
continue
fi
version_id=$(echo "$policy_details" | jq -r '.Ver')
attachment_count=$(echo "$policy_details" | jq -r '.Count')
if [ -z "$version_id" ]; then
echo " -> エラー: バージョンIDを取得できませんでした。スキップします。" >&2
continue
fi
is_used="None"
entities_list="N/A"
if [ "$attachment_count" -gt 0 ]; then
is_used="used"
entities_json=$(aws iam list-entities-for-policy --policy-arn "$arn" --output json)
entities_list=$(echo "$entities_json" | jq -r '
[
(.PolicyUsers[] | .UserName | "User:" + .),
(.PolicyGroups[] | .GroupName | "Group:" + .),
(.PolicyRoles[] | .RoleName | "Role:" + .)
] | join("; ")
')
else
is_used="None"
entities_list="None"
fi
policy_document_json=$(aws iam get-policy-version --policy-arn "$arn" --version-id "$version_id" \
--query 'PolicyVersion.Document' --output json)
if [ -z "$policy_document_json" ]; then
echo " -> エラー: ポリシードキュメントを取得できませんでした。スキップします。" >&2
continue
fi
csv_line=$(jq -n \
--arg name "$policy_name" \
--arg ver "$version_id" \
--arg used "$is_used" \
--arg entities "$entities_list" \
--argjson doc "$policy_document_json" \
'[ $name, $ver, $used, $entities, ($doc | tostring) ] | @tsv'
)
echo "$csv_line" >> "$OUTPUT_FILE"
done
処理フローとしては以下です
-
list-policiesでIAMポリシーの一覧を取得します -
get-policyでポリシーのメタデータ取得を取得します(ポリシーが何個アタッチされているかなどもこれでわかります) -
list-entities-for-policyでポリシーがアタッチされていれば、このリクエストでアタッチされているユーザーやグループなどがわかります -
get-policy-versionで実際のポリシー内容を確認することができます
最終的にこれまでの内容をtsv形式で出力するようにしています
(なぜtsvにしたかというと最終的にスプレッドシートに読み込ませようとした時にカンマ区切りのcsvだとインポートする際にうまく分けられなかったということがありました)
出力結果としては以下になります
本来であればAWS側で作成されたポリシーについては出力されません(aws iam list-policies --scope Localでローカルとしているからです)
policy_name\tversion_id\tused_as\tentities\tpolicy_detail
AWSCloudTrailAccessPolicy\tv1\tused\tNone\t{\"PolicyVersion\": {\"Document\": {\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Action\": \"iam:*\",\"Resource\": \"*\"}]},\"VersionId\": \"v2\",\"IsDefaultVersion\": true,\"CreateDate\": \"2023-04-11T00:22:54+00:00\"}}
.
.
.
.
おわりに
実際のスクリプトを貼るだけになってしまい、管理のところまで行けませんでしたがそこはいずれ形にしていければと思います
まずは出力した内容からどのように定期的にIAMを管理していくかを構想練るでも良い気がしますね
ではまた次の記事でお会いしましょう
