IAM ユーザーだけでなく IAM ロールも棚卸ししたい
コンバンハ、千葉(幸)です。
以前、IAM ユーザーを棚卸しする方法をまとめたことがありました。ここでは以下情報を取得することで IAM ユーザーがどのような権限を有しているかを確認しました。
- IAM ユーザーが所属する IAM グループの一覧
- IAM グループにアタッチされた管理ポリシーの一覧
- IAM グループにアタッチされたインラインポリシーの一覧
- IAM ユーザーに直接アタッチされた管理ポリシーの一覧
- IAM ユーザーに直接アタッチされたインラインポリシーの一覧
ここで、ひとが使う IAM エンティティとして IAM ユーザーでなく IAM ロールがメインの環境もあるでしょう。となると IAM ロールを対象に同じことをしたいです。とは言え、AWS サービスが使用する IAM ロールは別に対象に含みたくないです。
うまいことやる方法を考えました。
人が使う IAM ロールだけを抽出するアプローチ
AWS CLI コマンドのaws iam list-roles
でクエリをかけることで抽出します。
aws iam list-roles \
--query "Roles[?contains(AssumeRolePolicyDocument.Statement[0].to_string(Principal.AWS),\`arn:\`)].[RoleName]" --output text
aws iam list-roles
コマンドで信頼ポリシーの中身を取得できるので、プリンシパルが特定のものだけを引っ掛けます。
{
"Roles": [
{
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
},
"RoleId": "AROAJ52OTH4H7LEXAMPLE",
"CreateDate": "2013-05-11T00:02:27Z",
"RoleName": "ExampleRole1",
"Path": "/",
"Arn": "arn:aws:iam::123456789012:role/ExampleRole1"
},
...
IAM ロール信頼ポリシーでプリンシパルに指定できるものは以下ページに記載があります。
ここで、「種別がAWS
」「arn:
を含む」に合致するものを今回は抽出することにしました。
# | プリンシパル | 例 | 抽出対象 |
---|---|---|---|
1 | AWS アカウント | "AWS": "arn:aws:iam::123456789012:root" | はい *1 |
2 | IAM ロール | "AWS": "arn:aws:iam::AWS-account-ID:role/role-name" | はい |
3 | ロールセッション | "AWS": "arn:aws:sts::AWS-account-ID:assumed-role/role-name/role-session-name" | はい |
4 | ウェブ ID セッション | "Federated": "cognito-identity.amazonaws.com" | いいえ |
5 | SAML セッション | "Federated": "arn:aws:iam::AWS-account-ID:saml-provider/provider-name" | いいえ |
6 | IAM ユーザー | "AWS": "arn:aws:iam::AWS-account-ID:user/user-name" | はい |
7 | フェデレーテッドユーザー | "AWS": "arn:aws:sts::AWS-account-ID:federated-user/user-name" | はい |
8 | AWS サービス | "Service": "service-name.amazonaws.com" | いいえ |
9 | すべて | "AWS" : "*" | いいえ |
#4,#5 は普通に考えれば「人が使う IAM ロール」ですが、今回は対象外にしています。含めたい場合はコマンドをカスタマイズしてご利用ください。
また、例えば #2 IAM ロールを信頼する IAMロールがあったとして、それを人が使っているとは限りません。が、今回はそこを意識せず一律で抽出することにします。
ステートメントが複数ある場合は意図どおりにならない
例えば以下のような信頼ポリシーがあったとします。今回のコマンドでは一つ目のステートメントの Principal のみを評価するようにしているので、この信頼ポリシーを持つ IAM ロールは抽出対象になりません。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS-account-ID:user/user-name"
},
"Action": "sts:AssumeRole"
}
]
}
ステートメントが複数あったり「サービスからも IAM ユーザーからも引き受けできる」という状態であったりするケースは少ないと思いますが、今回のコマンドでは例外として扱いますのでご注意ください。
人が使う IAM ロール一覧を出力する
実際に先ほどのコマンドを実行してみます。いくつか結果が得られました。
% aws iam list-roles \
--query "Roles[?contains(AssumeRolePolicyDocument.Statement[0].to_string(Principal.AWS),\`arn:\`)].[RoleName]" --output text
AWS-QuickSetup-StackSet-Local-ExecutionRole
AWSCloudFormationStackSetExecutionRole
cm-chiba.yukihiro
cm-helpdesk
cm-membersportal
cm-policymaintainer
...
冒頭のふたつは人が使うものではありませんが、AWS アカウントであったり別の IAM ロールを信頼しているため結果に含まれてきています。このあたりをどう弾くかは環境にあわせて検討いただければと思います。
人が使う IAM ロールにアタッチされたポリシー一覧の取得
IAM ロールの一覧が取得できたので、これを用いて後続のコマンドを好きに実行できます。今回は、冒頭のエントリと同様にアタッチされたポリシーの一覧を取得してみます。
ポリシーは以下の種類に分かれており、それぞれ対応したコマンドが異なります。
- 管理ポリシー(AWS管理ポリシーおよびカスタマー管理ポリシー)
- インラインポリシー
管理ポリシー
echo "RoleName Policies" > /tmp/awscli.tmp
aws iam list-roles --query "Roles[?contains(AssumeRolePolicyDocument.Statement[0].to_string(Principal.AWS),\`arn:\`)].[RoleName]" --output text | sort | while read line;\
do
echo ${line} > /tmp/awscli-policy.tmp;\
aws iam list-attached-role-policies --role-name ${line} --query "AttachedPolicies[].[PolicyName]" --output text >> /tmp/awscli-policy.tmp;\
cat /tmp/awscli-policy.tmp | tr "\n" " " | sed 's/$/\n/g' >> /tmp/awscli.tmp;\
done
column -t /tmp/awscli.tmp;\
rm /tmp/awscli.tmp /tmp/awscli-policy.tmp
行っている処理の大枠は以下です。
/tmp/awscli.tmp
にヘッダーを出力- 人が使う IAM ロールの一覧を取得し、ロールごとに以下をループ
/tmp/awscli-policy.tmp
にユーザー名を出力(上書き)- ロールにアタッチされたポリシーの一覧を
/tmp/awscli-policy.tmp
に出力 /tmp/awscli-policy.tmp
の内容を「改行を除外」&「末尾に改行を付与」し/tmp/awscli.tmp
に出力(追記)
/tmp/awscli.tmp
の内容を表形式に整形する/tmp/awscli.tmp
と/tmp/awscli-group.tmp
を削除
実行した場合のイメージは以下です。
RoleName Policies
AWS-QuickSetup-StackSet-Local-ExecutionRole AdministratorAccess
AWSCloudFormationStackSetExecutionRole AdministratorAccess
cm-chiba.yukihiro AdministratorAccess CustomPolicy-A
cm-helpdesk ReadOnlyAccess
cm-membersportal ReadOnlyAccess
cm-policymaintainer
...
インラインポリシー
インラインポリシーの場合も途中で使用するコマンドが違うくらいで構成は同じです。
echo "RoleName InlinePolicies" > /tmp/awscli.tmp
aws iam list-roles --query "Roles[?contains(AssumeRolePolicyDocument.Statement[0].to_string(Principal.AWS),\`arn:\`)].[RoleName]" --output text | sort | while read line;\
do
echo ${line} > /tmp/awscli-policy.tmp;\
aws iam list-role-policies --role-name ${line} --query "PolicyNames[]" --output text >> /tmp/awscli-policy.tmp;\
cat /tmp/awscli-policy.tmp | tr "\n" " " | sed 's/$/\n/g' >> /tmp/awscli.tmp;\
done
column -t /tmp/awscli.tmp;\
rm /tmp/awscli.tmp /tmp/awscli-policy.tmp
終わりに
人が使う IAM ロールだけを一覧取得したい、という内容でした。
- 人が使うとは限らないものも含まれる
- ウェブ ID セッション、SAML セッション用のロールが対象に含まれない
- ステートメントが複数ある場合には対応していない
と、いくつか注意点がありますが、環境に合わせて細部をカスタマイズしていただければある程度は対応できるかと思います。
今回はアタッチされたポリシーを確認する、という内容に留めましたが、get-role と組み合わせて使用すれば「作成時刻」や「最終使用時刻」の取得も可能です。
参考になれば幸いです。
以上、 チバユキ (@batchicchi) がお送りしました。
参考
脚注
- AWS アカウントプリンシパルは`"AWS": "123456789012"`の形式にも対応しており、その形式で保存されていた場合は抽出対象になりません。基本的には`"AWS": "arn:aws:iam::123456789012:root"`の形式に変換されるようですが、すべてが変換対象と保証はされていなさそうです。 ↩