0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(Part 1)使っていない AWS IAMの管理をしたい(お金かけずに)

Posted at

概要

AWSやGoogle Cloudを使用していると、IAMロールやIAMポリシーを過剰な権限で作成したりいつの間にか知らないIAMポリシーを放置してしまったりということが多くあると思います(特に開発環境ではとりあえず作って放置してしまいがちです)

今回はAWSに焦点を当てて不要なIAMを一覧化して整理の手助けできるようにできないかを検討してみたいと思います

本題

軽く考えたなかでのアプローチとしては

  1. IAM Access Analyzerを使って分析する
  2. 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) ポリシー変更が、事前に定義した企業のセキュリティ基準や特定の要件に違反していないかを検証します。 組織独自のセキュリティ基準をポリシーレビュープロセスに組み込む。 有料

今回やりたいこと的には「未使用アクセス検出」というのが適していそうだと思いました

ただ、ここで気になるところとしては有料というところかと思われます

実際に公式のドキュメントを確認すると以下のような料金形態となっております

スクリーンショット 2025-10-29 23.31.22.png

ap-northeast-1での計算ですが、 1つのIAMロールまたはユーザーIAMにつき0.2USDだそうです

開発環境などで実行するとかなりの料金になる気がします

またIAMポリシーについては不要かどうかを判別する方法はなさそうでした

ということで手間ではありますがこういう小さなところから節約を積み重ねたり、コーディングについて考えられる機会だと思って次に進んでいきたいと思います

CLI or Pythonで処理を考える

Pythonまで手が回らず、とりあえずCLIベースのところが完成したので、そこを説明したいと思います

スクリプト本体は以下になります
別途インストールが必要なものはjqaws-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

処理フローとしては以下です

  1. list-policiesでIAMポリシーの一覧を取得します
  2. get-policyでポリシーのメタデータ取得を取得します(ポリシーが何個アタッチされているかなどもこれでわかります)
  3. list-entities-for-policyでポリシーがアタッチされていれば、このリクエストでアタッチされているユーザーやグループなどがわかります
  4. 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を管理していくかを構想練るでも良い気がしますね

ではまた次の記事でお会いしましょう

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?