AWSマネージドなポリシーの中で特定のActionをもつポリシーを逆引き検索したかったので python + boto3 でやってみた

# やりたいこと

例えば以下はAmazonEKSAdminPolicyのjsonなのですが、

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "eks:*" # ここ
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "eks.amazonaws.com"
                }
            }
        }
    ]
}
```

Actionの中に上記のようにeksに関するActionを持つポリシーを探したい、という要件がありました。
しかし、マネージメントコンソール上からこのような検索はできないようだったので、python + boto3で検索するスクリプトを作ってみました。

# どのサービスがどのActionを持ってるか調べる方法

サービスごとに対応するActionの一覧のページがあるので以下を参照してください。

https://docs.aws.amazon.com/ja_jp/service-authorization/latest/reference/reference_policies_actions-resources-contextkeys.html

# pythonコード
KEYWORDに検索したいActionの文字列を入れて実行してください。キーワードは部分一致で検索しているので`eks:DeleteAddon`とかでも大丈夫です。

以下のコードではaws_access_key_idとaws_secret_access_keyは埋め込んでしまっていますが渡し方等は適宜修正してください。

boto3を使うので事前にinstallしてください。

```
pip install boto3
```

以下特定のActionをもつポリシーを逆引きするpythonコード。

```
# -*- coding: utf-8 -*-
import boto3
import json
from collections import defaultdict

# 検索したいAction
KEYWORD = "eks:" 

# boto3を使用してIAMクライアントを作成する
# 認証情報の渡し方は適宜変更

client = boto3.client(
    'iam',
    aws_access_key_id="*****************",
    aws_secret_access_key="*****************" ,
)

# IAMポリシーのリストを取得する
_policies = client.list_policies(Scope='AWS', MaxItems=1000)
policies = _policies['Policies']
print('.', end="")
while 'IsTruncated' in _policies and _policies['IsTruncated']:
    _policies = client.list_policies(Scope='AWS', MaxItems=1000, Marker=_policies['Marker'])
    policies += _policies['Policies']
    print('.', end="")
print('.')


# ARNを使用してポリシーのバージョンからドキュメントを取得する
result_arns = defaultdict(list)
policy_versions = []
for p in policies:
    policy_version = client.get_policy_version(PolicyArn=p['Arn'],  VersionId=p['DefaultVersionId'])['PolicyVersion']
    policy_document = policy_version['Document']
    policy_statement = policy_document['Statement']

    if type(policy_statement) != list:
        policy_statement = [policy_statement]
    for s in policy_statement:
        try:
            if not 'Action' in s:
                continue
            if type(s['Action']) is list:
                for a in s['Action']:
                    if KEYWORD in a:
                        result_arns[p['Arn']].append(a)
            elif type(s['Action']) is str:
                if KEYWORD in s['Action']:
                    result_arns[p['Arn']].append(s['Action'])
        except Exception as e:
            print(e)

# 結果出力
for arn, actions in result_arns.items():
    print(f"# {arn}")
    for action in actions:
        print(action)
```

ここではAWSマネージドなポリシーのみに絞って検索したかったので

```
client.list_policies(Scope='AWS', MaxItems=1000)
```

としていますが、自分で作ったものも含めて検索する場合は`Scope='All'`に書き換えると可能です。

# 結果
以下のように対象の文字列を含むactionがそのポリシーのarnごとに出力されます。

```
...
# arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
eks:DescribeCluster
# arn:aws:iam::aws:policy/aws-service-role/AmazonGuardDutyServiceRolePolicy
eks:ListClusters
eks:DescribeCluster
eks:CreateAddon
eks:DeleteAddon
eks:UpdateAddon
eks:DescribeAddon
eks:TagResource
# arn:aws:iam::aws:policy/ReadOnlyAccess
eks:Describe*
eks:List*
# arn:aws:iam::aws:policy/SecurityAudit
eks:DescribeCluster
eks:DescribeNodeGroup
eks:ListClusters
eks:ListNodeGroups
# arn:aws:iam::aws:policy/AWSBatchFullAccess
eks:DescribeCluster
eks:ListClusters
# arn:aws:iam::aws:policy/aws-service-role/AWSSupportServiceRolePolicy
eks:describeCluster
eks:describeFargateProfile
eks:describeNodegroup
eks:describeUpdate
eks:listAddons
eks:listClusters
eks:listFargateProfiles
eks:listNodegroups
eks:listUpdates
# arn:aws:iam::aws:policy/AmazonEKSServicePolicy
eks:UpdateClusterVersion
# arn:aws:iam::aws:policy/aws-service-role/CloudwatchApplicationInsightsServiceLinkedRolePolicy
eks:DescribeCluster
eks:DescribeFargateProfile
eks:DescribeNodegroup
eks:ListClusters
eks:ListFargateProfiles
eks:ListNodegroups
# arn:aws:iam::aws:policy/aws-service-role/AWSConfigServiceRolePolicy
eks:DescribeAddon
eks:DescribeCluster
eks:DescribeFargateProfile
eks:DescribeIdentityProviderConfig
eks:DescribeNodegroup
eks:ListAddons
eks:ListClusters
eks:ListFargateProfiles
eks:ListIdentityProviderConfigs
eks:ListNodegroups
eks:ListTagsForResource
# arn:aws:iam::aws:policy/aws-service-role/BatchServiceRolePolicy
eks:DescribeCluster
# arn:aws:iam::aws:policy/aws-service-role/AmazonGuardDutyMalwareProtectionServiceRolePolicy
eks:DescribeCluster
# arn:aws:iam::aws:policy/aws-service-role/AmazonFISServiceRolePolicy
eks:DescribeNodegroup
eks:DescribeCluster
# arn:aws:iam::aws:policy/CloudWatchApplicationInsightsFullAccess
eks:ListClusters
eks:ListNodegroups
# arn:aws:iam::aws:policy/aws-service-role/AmazonEMRContainersServiceRolePolicy
eks:DescribeCluster
eks:ListNodeGroups
eks:DescribeNodeGroup
# arn:aws:iam::aws:policy/service-role/AWS_ConfigRole
eks:DescribeAddon
eks:DescribeCluster
eks:DescribeFargateProfile
eks:DescribeIdentityProviderConfig
eks:DescribeNodegroup
eks:ListAddons
eks:ListClusters
eks:ListFargateProfiles
eks:ListIdentityProviderConfigs
eks:ListNodegroups
eks:ListTagsForResource
```

おわり