AWSの組織(Organizations)でIAM Access Analyzer の未使用の許可のスキャン対象となるユーザーとロールを算出してみた

2024.02.15

IAM Access Analyzer で未使用のアクセス権を組織(Organizations)全体で検出してみた の際に、実際にどれくらい料金がかかるか不安だったので試算してみました。

スキャン対象となるIAMユーザー、ロールの算出

AWS Resouce Explore を使う方法

対象となるユーザまたロールが1000件以下であれば、

AWS Organizationsにて、マルチアカウントのView(インデクス)が作成されていれば、AWS Resource Explorer から対象となる IAMユーザ、またIAMロールは簡単に検出できます。

以下の検索文でResouce Exploreにて対象となるIAMユーザ、IAMロールを抽出してください

AWS Resource Explorer > リソースの検索
https://resource-explorer.console.aws.amazon.com/resource-explorer/home?region=ap-northeast-1#/search

必要に応じて、「ビューを変更」を選択して、AWS Organizations全体のビュー(マルチアカウントビュー)を選択します

マルチアカウントのビューの作成方法はこちらの記事をご参考ください https://dev.classmethod.jp/articles/aws-resource-explorer-multi-account-view/

IAMロールを検索

検索クエリに resourcetype:iam:role

を入力し、検索してください

IAMユーザーを検索

検索クエリに resourcetype:iam:user

を入力し、検索してください

リソース数に抽出されたリソースの件数が表示されます。

なお、AWS Resource Explorerの制限により検索結果が1000件を超える場合は、総数は算出できませんのでご注意ください。 その際は以下でご案内する 各アカウントにスイッチロールをして総数を算出する方法をご参考にしてください

各アカウントにスイッチロールをして総数を算出する方法

管理アカウントより各アカウントにAWSControlTowerExecution もしくは、OrganizationAccountAccessRoleへスイッチロールを行い、ユーザーとロールの総数を算出してみます。 サンプルシェルスクリプトを作成したので、ご活用ください。

なお、アカウント内にOrganizationAccountAccessRole がない場合は、StackSetsなどを利用して、対象のアカウントにロールを作成してロール名を変更してください。

管理アカウントにログインしCloudShellより実行を行います。

シェルの中身は

  1. 組織内のアカウント一覧を取得
  2. アカウントごとにIAMユーザーとIAMロールの数を集計
    1. AWSControlTowerExecutionにスイッチロール
      1. スイッチロールに失敗した場合(Control Tower 有効化済みでない場合)OrganizationAccountAccessRoleを使用します。
    2. IAMユーザーとIAMロールの数を取得
  3. 組織全体のIAMユーザーとIAMロールの合計を表示
  4. アカウントの総数を表示
  5. アカウントのIAMユーザー数とIAMロールの平均を計算して表示

となります

シェルスクリプト

#!/bin/bash

# 組織内のアカウント一覧を取得
account_list=$(aws organizations list-accounts --output json | jq -r '.Accounts[] | .Id')

# 組織全体のIAMユーザーとIAMロールの数を初期化
total_users_count=0
total_roles_count=0
account_count=0

# アカウントごとにIAMユーザーとIAMロールの数を集計
for account_id in $account_list
do
  # 環境変数をクリア
  unset AWS_ACCESS_KEY_ID
  unset AWS_SECRET_ACCESS_KEY
  unset AWS_SESSION_TOKEN

  echo "Account ID: $account_id"

  # アカウント名を取得
  account_name=$(aws organizations describe-account --account-id $account_id --output json | jq -r '.Account.Name')
  echo "Account Name: $account_name"

  # AWSControlTowerExecutionにスイッチロール
  role_session_name="tempSession"
  credentials=$(aws sts assume-role --role-arn arn:aws:iam::$account_id:role/AWSControlTowerExecution --role-session-name $role_session_name 2>&1)

  if [ $? -ne 0 ]; then
    echo "AWSControlTowerExecutionへのAssumeRoleに失敗しました。OrganizationAccountAccessRoleを使用します。"
    role_session_name="tempSession"
    role_name="OrganizationAccountAccessRole"
    role_arn="arn:aws:iam::$account_id:role/$role_name"
    credentials=$(aws sts assume-role --role-arn $role_arn --role-session-name $role_session_name)
  fi

  export AWS_ACCESS_KEY_ID=$(echo $credentials | jq -r '.Credentials.AccessKeyId')
  export AWS_SECRET_ACCESS_KEY=$(echo $credentials | jq -r '.Credentials.SecretAccessKey')
  export AWS_SESSION_TOKEN=$(echo $credentials | jq -r '.Credentials.SessionToken')

  # IAMユーザーとIAMロールの数を取得
  users_count=$(aws iam list-users --output json | jq '.Users | length')
  roles_count=$(aws iam list-roles --output json | jq '.Roles | length')

  echo "IAMユーザーの数: $users_count"
  echo "IAMロールの数: $roles_count"

  # 組織全体の合計に加算
  total_users_count=$((total_users_count + users_count))
  total_roles_count=$((total_roles_count + roles_count))
  account_count=$((account_count + 1))

done

# 組織全体のIAMユーザーとIAMロールの合計を表示
echo "組織全体のIAMユーザーの合計: $total_users_count"
echo "組織全体のIAMロールの合計: $total_roles_count"

# アカウントの総数を表示
echo "アカウントの総数: $account_count"

# 平均を計算して表示
average_users_count=$((total_users_count / account_count))
average_roles_count=$((total_roles_count / account_count))
echo "組織全体のIAMユーザーの平均: $average_users_count"
echo "組織全体のIAMロールの平均: $average_roles_count"

シェルスクリプト(各アカウントに1000件以上のユーザー、ロールがある場合)

1000件のページネーションを行うようにしています。

#!/bin/bash

# 組織内のアカウント一覧を取得
account_list=$(aws organizations list-accounts --output json | jq -r '.Accounts[] | .Id')

# 組織全体のIAMユーザーとIAMロールの数を初期化
total_users_count=0
total_roles_count=0
account_count=0

# アカウントごとにIAMユーザーとIAMロールの数を集計
for account_id in $account_list
do
  # 環境変数をクリア
  unset AWS_ACCESS_KEY_ID
  unset AWS_SECRET_ACCESS_KEY
  unset AWS_SESSION_TOKEN

  echo "Account ID: $account_id"

  # アカウント名を取得
  account_name=$(aws organizations describe-account --account-id $account_id --output json | jq -r '.Account.Name')
  echo "Account Name: $account_name"

  # AWSControlTowerExecutionにスイッチロール
  role_session_name="tempSession"
  credentials=$(aws sts assume-role --role-arn arn:aws:iam::$account_id:role/AWSControlTowerExecution --role-session-name $role_session_name 2>&1)

  if [ $? -ne 0 ]; then
    echo "AWSControlTowerExecutionへのAssumeRoleに失敗しました。OrganizationAccountAccessRoleを使用します。"
    role_session_name="tempSession"
    role_name="OrganizationAccountAccessRole"
    role_arn="arn:aws:iam::$account_id:role/$role_name"
    credentials=$(aws sts assume-role --role-arn $role_arn --role-session-name $role_session_name)
  fi

  export AWS_ACCESS_KEY_ID=$(echo $credentials | jq -r '.Credentials.AccessKeyId')
  export AWS_SECRET_ACCESS_KEY=$(echo $credentials | jq -r '.Credentials.SecretAccessKey')
  export AWS_SESSION_TOKEN=$(echo $credentials | jq -r '.Credentials.SessionToken')

  # ページネーション処理を含めてIAMユーザーとIAMロールの数を取得
  users_count=0
  next_token=""
  while true; do
    response=$(aws iam list-users --output json --max-items 1000 $([ -n "$next_token" ] && echo "--starting-token $next_token"))
    users_count=$((users_count + $(echo $response | jq '.Users | length')))
    next_token=$(echo $response | jq -r '.NextToken')
    [ "$next_token" = "null" ] && break
  done

  roles_count=0
  next_token=""
  while true; do
    response=$(aws iam list-roles --output json --max-items 1000 $([ -n "$next_token" ] && echo "--starting-token $next_token"))
    roles_count=$((roles_count + $(echo $response | jq '.Roles | length')))
    next_token=$(echo $response | jq -r '.NextToken')
    [ "$next_token" = "null" ] && break
  done

  echo "IAMユーザーの数: $users_count"
  echo "IAMロールの数: $roles_count"

  # 組織全体の合計に加算
  total_users_count=$((total_users_count + users_count))
  total_roles_count=$((total_roles_count + roles_count))
  account_count=$((account_count + 1))

done

# 組織全体のIAMユーザーとIAMロールの合計を表示
echo "組織全体のIAMユーザーの合計: $total_users_count"
echo "組織全体のIAMロールの合計: $total_roles_count"

# アカウントの総数を表示
echo "アカウントの総数: $account_count"

# 平均を計算して表示
average_users_count=$((total_users_count / account_count))
average_roles_count=$((total_roles_count / account_count))
echo "組織全体のIAMユーザーの平均: $average_users_count"
echo "組織全体のIAMロールの平均: $average_roles_count"

実行結果

Account ID: XXXXXXXXXXXX
Account Name:  Acount XXXXXXXXXXXX 
AWSControlTowerExecutionへのAssumeRoleに失敗しました。OrganizationAccountAccessRoleを使用します。

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/AWSReservedSSO_AWSAdministratorAccess_xxxx is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::XXXXXXXXXXXX:role/OrganizationAccountAccessRole
IAMユーザーの数: 0
IAMロールの数: NN

Account ID: AAAAAAAAAAAA
Account Name: Acount AAAAAAAAAAAA
IAMユーザーの数: 0
IAMロールの数: NN

Account ID: BBBBBBBBBBBB
Account Name: Acount BBBBBBBBBBBB
IAMユーザーの数: 2
IAMロールの数: NN

Account ID: CCCCCCCCCCCC
Account Name: Acount CCCCCCCCCCCC
IAMユーザーの数: 0
IAMロールの数: NN

組織全体のIAMユーザーの合計: 2
組織全体のIAMロールの合計: NNN
アカウントの総数: 4
組織全体のIAMユーザーの平均: 0
組織全体のIAMロールの平均: AVG

※組織全体のアカウントで動かしているので、管理アカウント自体の場合はスイッチロールに失敗していますが、シェルを実行している際の権限を使用します。

現時点(2024/02)では、以下の料金表により 0.20USD x 分析された IAM ロールまたはユーザー/月となります。

0.20USD x 分析された IAM ロールまたはユーザー/月

IAM Access Analyzer の料金

AWS Pricing Calculator で試算する

なお、月あたりの試算はAWS Pricing Calculator でも計算できますので、ご参考ください

https://calculator.aws/#/createCalculator/IAMAccessAnalyzer

スキャン対象のアカウント数、平均ロール数、平均ユーザー数を入力して計算します。 トータルコストの欄に試算額が表示されます。

参考

AWS Identity and Access Management Access Analyzer の結果の使用開始
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access-analyzer-getting-started.html

https://dev.classmethod.jp/articles/script-to-create-delete-all-regions-of-iam-access-analyzer/