こんにちは!
エンタープライズクラウド部技術2課の日高です。
今回は「IAMグループとIAMユーザー設定を視覚化するスクリプト」を作成したので、そちらについてブログを記載しようと思います。
- はじめに
- 前提と作成したスクリプト解説
- スクリプトの詳細
- 1. シェバングとオプション
- 2. プロファイルの定義
- 3. IAMグループの情報を取得する関数
- 4. 引数の受け取り
- 5. グループに関連付けられたユーザーの取得
- 6. グループにアタッチされた管理ポリシーの取得
- 7. グループのインラインポリシーの取得
- 8. 取得した情報の出力
- 9. IAMユーザーの情報を取得する関数
- 10. 引数の受け取り
- 11. ユーザーが所属するグループの取得
- 12. ユーザーにアタッチされた管理ポリシーの取得
- 13. ユーザーのインラインポリシーの取得
- 14. ユーザーのマネジメントコンソールへのアクセス許可の確認
- 15. ユーザーのAWS CLIへのアクセス許可の確認
- 16. ユーザーのMFA (多要素認証) の設定状況の確認
- 17. 取得した情報の出力
- 18. 関数のエクスポート
- 19. メインの処理部分
- 20. 出力ファイル名の設定
- 21-30. IAMの情報の取得とファイルへの出力
- 31. 処理終了の通知
- まとめ
はじめに
最近、多くのお客様から以下のようなお悩みをいただいています。
- AWSで運用を開始してからある程度の時間が経過し、現在はIAMユーザーやIAMポリシーが増えてしまい、これらが散乱している状態。そのため統制が十分に取れておらず、管理が困難になっている。
- 現状どのような設定になっているかを一括で確認したい。
このような状態はセキュリティインシデントを引き起こす大きなリスクを伴います。
そのため、IAMグループとIAMユーザーの現状の設定を視覚化できるスクリプトを作成してみました。
本ブログで作成したスクリプトについて解説していきます。
前提と作成したスクリプト解説
前提
- AWS CLIがインストールされている
- スイッチロールできる設定が済まされている(AWS CLI の設定 (~/.aws/config ファイル) にて、ロールの情報が設定されている)
- 実行環境のOSがMacOS
※スイッチロールではなく、デフォルトに設定されているアカウントでスクリプトを実行したい場合は、スクリプトの「PROFILE="指定してください"」と「--profile $PROFILE」を削除して利用してください。
また、筆者の実行環境(OSとシェル)は以下です。
% sw_vers ProductName: macOS ProductVersion: 14.0 BuildVersion: 23A344 % bash --version GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23) Copyright (C) 2007 Free Software Foundation, Inc.
作成したスクリプト
このスクリプトは、指定したAWSアカウントに関するIAMの詳細をマークダウンの表形式で出力します。
具体的には、IAMグループの情報として、そのグループに関連付けられているIAMユーザー、管理ポリシー(AWS管理ポリシーとカスタムポリシーの両方)、そしてインラインポリシーを把握できます。
さらに、IAMユーザーの詳細に関しても、該当ユーザーが関連しているIAMグループ、管理ポリシー、インラインポリシーの他、マネジメントコンソールやAWS CLIへのアクセス許可、そして多要素認証(MFA)の設定状況も確認できるようになっています。
#!/bin/bash -eu PROFILES=("指定してください" "指定してください" ....n ) # この配列にプロファイル名を追加してください。 get_group_info() { local profile="$1" local group="$2" users=$(aws iam get-group --profile "$profile" --group-name "$group" --query "Users[].[UserName]" --output text | tr '\n' ',' | sed 's/,$//') managed_policies=$(aws iam list-attached-group-policies --profile "$profile" --group-name "$group" --query "AttachedPolicies[].[PolicyName]" --output text | tr '\n' ',' | sed 's/,$//') inline_policies=$(aws iam list-group-policies --profile "$profile" --group-name "$group" --query "PolicyNames[]" --output text | tr '\n' ',' | sed 's/,$//') echo "| $group | [$users](mailto:$users) | $managed_policies | $inline_policies |" } get_user_info() { local profile="$1" local user="$2" groups=$(aws iam list-groups-for-user --profile "$profile" --user-name "$user" --query "Groups[].[GroupName]" --output text | tr '\n' ',' | sed 's/,$//') managed_policies=$(aws iam list-attached-user-policies --profile "$profile" --user-name "$user" --query "AttachedPolicies[].[PolicyName]" --output text | tr '\n' ',' | sed 's/,$//') inline_policies=$(aws iam list-user-policies --profile "$profile" --user-name "$user" --query "PolicyNames[]" --output text | tr '\n' ',' | sed 's/,$//') login_profile=$(aws iam get-login-profile --profile "$profile" --user-name "$user" --query "LoginProfile.UserName" --output text 2>/dev/null) if [ "$login_profile" == "$user" ]; then console_access="Yes" else console_access="No" fi access_keys=$(aws iam list-access-keys --profile "$profile" --user-name "$user" --query "AccessKeyMetadata[?Status=='Active'].[AccessKeyId]" --output text) if [ -z "$access_keys" ]; then cli_access="No" else cli_access="Yes" fi mfa_devices=$(aws iam list-mfa-devices --profile "$profile" --user-name "$user" --query "MFADevices[].[SerialNumber]" --output text) if [ -z "$mfa_devices" ]; then mfa_status="Not Enabled" else mfa_status="Enabled" fi echo "| $user | $groups | $managed_policies | $inline_policies | $console_access | $cli_access | $mfa_status |" } export -f get_group_info export -f get_user_info for PROFILE in "${PROFILES[@]}"; do OUTPUT_FILE="${PROFILE}_iam_assessment.md" { echo "## IAM Groups for $PROFILE" echo "| Group Name | Users | Managed Policy | Inline Policy |" echo "| :---: | :---: | :---: | :---: |" aws iam list-groups --profile "$PROFILE" --query "Groups[].[GroupName]" --output text | xargs -I {} bash -c 'get_group_info "$0" "$1"' "$PROFILE" "{}" echo "" echo "## IAM Users for $PROFILE" echo "| User Name | IAM Groups | Managed Policy | Inline Policy | Management Console Access | CLI Access | MFA Status |" echo "| :---: | :---: | :---: | :---: | :---: | :---: | :---: |" aws iam list-users --profile "$PROFILE" --query "Users[].[UserName]" --output text | xargs -I {} bash -c 'get_user_info "$0" "$1"' "$PROFILE" "{}" } > $OUTPUT_FILE echo "IAM assessment for $PROFILE saved to $OUTPUT_FILE" done
利用方法
準備
- 上記のスクリプトを実行するフォルダ配下に作成する。
※この際PROFILES
はご自身が実行したいものに書き換えてください。
実行コマンド
- 下記コマンドを実行します。
- bash <保存時のスクリプト名>
- 私の場合は「assessment-iam.sh」で保存しているのでbash assessment-iam.shが実行コマンドになります。
スクリプトの実行結果
Typoraというテキストエディタでマークダウン形式からテキスト形式に変換して出力していますが以下のようになります。
上記のように、IAMグループの情報として、そのグループに関連付けられているIAMユーザー、管理ポリシー(AWS管理ポリシーとカスタムポリシーの両方)、そしてインラインポリシーを把握できます。
さらに、IAMユーザーの詳細に関しても、該当ユーザーが関連しているIAMグループ、管理ポリシー、インラインポリシーの他、マネジメントコンソールやAWS CLIへのアクセス許可、そして多要素認証(MFA)の設定状況も確認することができます。
スクリプトの詳細
下記でスクリプトの解説をします。
1. シェバングとオプション
#!/bin/bash -eu
シェルスクリプト: この行はシェバングと呼ばれるもので、スクリプトを実行する際のシェルをbashとして指定しています。-eu
オプションは、スクリプト内でエラーが発生したり未定義の変数が使われた時にスクリプトを終了させるためのものです。
2. プロファイルの定義
PROFILES=("指定してください" "指定してください" ....n )
シェルスクリプト: AWS CLIのプロファイル名を格納する配列を定義しています。ユーザーはこの配列に独自のプロファイル名を追加することが期待されています。
3. IAMグループの情報を取得する関数
get_group_info() {
シェルスクリプト: get_group_info
関数の定義を開始しています。この関数はIAMグループに関連する情報を取得します。
4. 引数の受け取り
local profile="$1" local group="$2"
シェルスクリプト: 関数に渡された2つの引数(AWS CLIのプロファイル名とIAMグループ名)をローカル変数に代入しています。
5. グループに関連付けられたユーザーの取得
users=$(aws iam get-group --profile "$profile" --group-name "$group" --query "Users[].[UserName]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam get-group
コマンドを使用して、指定されたプロファイルとグループ名でIAMグループに関連付けられたユーザーのリストを取得しています。
シェルスクリプト: 続いて、tr
とsed
コマンドを用いて、取得したユーザーのリストをカンマで区切り、末尾のカンマを削除しています。
6. グループにアタッチされた管理ポリシーの取得
managed_policies=$(aws iam list-attached-group-policies --profile "$profile" --group-name "$group" --query "AttachedPolicies[].[PolicyName]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam list-attached-group-policies
コマンドを使用して、指定されたプロファイルとグループ名でIAMグループにアタッチされている管理ポリシーのリストを取得しています。
シェルスクリプト: ユーザーの取得と同様に、ポリシーのリストをカンマで区切り、末尾のカンマを削除しています。
7. グループのインラインポリシーの取得
inline_policies=$(aws iam list-group-policies --profile "$profile" --group-name "$group" --query "PolicyNames[]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam list-group-policies
コマンドを使用して、指定されたプロファイルとグループ名でIAMグループに関連するインラインポリシーのリストを取得しています。
シェルスクリプト: これも同様に、ポリシーのリストをカンマで区切り、末尾のカンマを削除しています。
8. 取得した情報の出力
echo "| $group | [$users](mailto:$users) | $managed_policies | $inline_policies |"
シェルスクリプト: 前述の変数を使用して、マークダウン形式のテーブル行を出力しています。ユーザー名はメールリンクとしてフォーマットされています。
9. IAMユーザーの情報を取得する関数
get_user_info() {
シェルスクリプト: get_user_info
関数の定義を開始しています。この関数はIAMユーザーに関連する情報を取得します。
10. 引数の受け取り
local profile="$1" local user="$2"
シェルスクリプト: 関数に渡された2つの引数(AWS CLIのプロファイル名とIAMユーザー名)をローカル変数に代入しています。
11. ユーザーが所属するグループの取得
groups=$(aws iam list-groups-for-user --profile "$profile" --user-name "$user" --query "Groups[].[GroupName]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam list-groups-for-user
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーが所属するグループのリストを取得しています。 シェルスクリプト: これも、グループのリストをカンマで区切り、末尾のカンマを削除しています。
12. ユーザーにアタッチされた管理ポリシーの取得
managed_policies=$(aws iam list-attached-user-policies --profile "$profile" --user-name "$user" --query "AttachedPolicies[].[PolicyName]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam list-attached-user-policies
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーにアタッチされている管理ポリシーのリストを取得しています。 シェルスクリプト: 同様に、ポリシーのリストをカンマで区切り、末尾のカンマを削除しています。
13. ユーザーのインラインポリシーの取得
inline_policies=$(aws iam list-user-policies --profile "$profile" --user-name "$user" --query "PolicyNames[]" --output text | tr '\n' ',' | sed 's/,$//')
AWS CLI: aws iam list-user-policies
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーに関連するインラインポリシーのリストを取得しています。 シェルスクリプト: これも、ポリシーのリストをカンマで区切り、末尾のカンマを削除しています。
14. ユーザーのマネジメントコンソールへのアクセス許可の確認
login_profile=$(aws iam get-login-profile --profile "$profile" --user-name "$user" --query "LoginProfile.UserName" --output text 2>/dev/null)
AWS CLI: aws iam get-login-profile
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーのログインプロファイルを取得しています。この情報を使用して、ユーザーがAWSマネジメントコンソールへのアクセス権を持っているかどうかを確認します。
if [ "$login_profile" == "$user" ]; then console_access="Yes" else console_access="No" fi
シェルスクリプト: get-login-profile
コマンドの結果を確認して、ユーザーがマネジメントコンソールにアクセスできるかどうかを判断しています。
15. ユーザーのAWS CLIへのアクセス許可の確認
access_keys=$(aws iam list-access-keys --profile "$profile" --user-name "$user" --query "AccessKeyMetadata[?Status=='Active'].[AccessKeyId]" --output text)
AWS CLI: aws iam list-access-keys
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーのアクセスキーを取得しています。
if [ -z "$access_keys" ]; then cli_access="No" else cli_access="Yes" fi
シェルスクリプト: 取得したアクセスキーの有無を確認して、ユーザーがAWS CLIにアクセスできるかどうかを判断しています。
16. ユーザーのMFA (多要素認証) の設定状況の確認
mfa_devices=$(aws iam list-mfa-devices --profile "$profile" --user-name "$user" --query "MFADevices[].[SerialNumber]" --output text)
AWS CLI: aws iam list-mfa-devices
コマンドを使用して、指定されたプロファイルとユーザー名でIAMユーザーのMFAデバイスを取得しています。
if [ -z "$mfa_devices" ]; then mfa_status="Not Enabled" else mfa_status="Enabled" fi
シェルスクリプト: 取得したMFAデバイスの有無を確認して、ユーザーがMFAを有効にしているかどうかを判断しています。
17. 取得した情報の出力
echo "| $user | $groups | $managed_policies | $inline_policies | $console_access | $cli_access | $mfa_status |"
シェルスクリプト: 前述の変数を使用して、マークダウン形式のテーブル行を出力しています。
18. 関数のエクスポート
export -f get_group_info export -f get_user_info
シェルスクリプト: 現在のシェルセッションに関数をエクスポートしています。これにより、xargs
経由でのサブシェルからもこれらの関数を呼び出すことができます。
19. メインの処理部分
for PROFILE in "${PROFILES[@]}"; do
シェルスクリプト: PROFILES
配列に格納されている各プロファイルに対してループ処理を開始しています。
20. 出力ファイル名の設定
OUTPUT_FILE="${PROFILE}_iam_assessment.md"
シェルスクリプト: 各プロファイルに対する出力ファイル名を設定しています。
21-30. IAMの情報の取得とファイルへの出力
{ ... } > $OUTPUT_FILE
シェルスクリプト: {...}
ブロック内のコマンドの出力を$OUTPUT_FILE
にリダイレクトしています。このブロック内では、前述のget_group_info
およびget_user_info
関数を使用してIAMの情報を取得し、マークダウン形式で出力しています。
31. 処理終了の通知
echo "IAM assessment for $PROFILE saved to $OUTPUT_FILE"
シェルスクリプト: 各プロファイルに対するIAMの評価結果がどのファイルに保存されたかを通知しています。
まとめ
権限整理をする際などにご利用いただけると嬉しいです。
本ブログが誰かの助けになっていれば幸いです。
日高 僚太(執筆記事の一覧)
EC部技術2課 / AWS認定資格 12冠
2022年IT未経験で新卒入社しました。
最近はダーツとサウナが気になっています!
記事に関するお問い合わせや修正依頼⇒ hidaka@serverworks.co.jp