IAMポリシーをチェックできるスクリプトを作った

Published
2022-10-17
Author
ykich
Tags

定義済みのIAMポリシーに対して、構文エラーや警告がないか、チェックするAPIをつくったので、紹介します。

Motivation

IAMポリシーをTerraformなどで作成していると、たとえ間違ったアクションを許可していてもエラーなく作成できてしまいます。

実際に使うタイミングで発覚することも多いです。

AWSマネジメントコンソールのJSONエディタでは、きちんとエラー表示してくれます。

ポリシーが多くなってくると、1件1件このように確認していくのは大変です。

幸いにも「accessanalyzer」サービスの「validate-policy」APIが公開されているので、こちらを使えば一括でチェックするスクリプトが作れそうなので、今回作ってみました。 AWSドキュメント:https://docs.aws.amazon.com/cli/latest/reference/accessanalyzer/validate-policy.html


validate_policy.py

import json
import boto3

aa = boto3.client('accessanalyzer')
iam = boto3.client('iam')

list_policies = iam.list_policies()
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.list_policies

LIMIT = 10000
cnt = 0
for policy in list_policies["Policies"]:
    # filter policy
    if not ("<system-name>" in policy["Arn"]):
        continue

    get_policy = iam.get_policy(
        PolicyArn=policy["Arn"]
    )
    print(policy["Arn"])

    policy_version = iam.get_policy_version(
        PolicyArn=policy["Arn"],
        VersionId=get_policy['Policy']['DefaultVersionId']
    )
    doc = json.dumps(policy_version['PolicyVersion']['Document'])

    validate = aa.validate_policy(
        locale='JA',
        policyDocument=doc,
        policyType='IDENTITY_POLICY',  # | 'RESOURCE_POLICY' | 'SERVICE_CONTROL_POLICY',
        # validatePolicyResourceType='AWS::S3::Bucket' | 'AWS::S3::AccessPoint' | 'AWS::S3::MultiRegionAccessPoint' | 'AWS::S3ObjectLambda::AccessPoint' | 'AWS::IAM::AssumeRolePolicyDocument'
    )
    # https://docs.aws.amazon.com/cli/latest/reference/accessanalyzer/validate-policy.html

    for find in validate['findings']:
        exclude_code = ["REDUNDANT_STATEMENT", "EMPTY_SID_VALUE"]
        if find["issueCode"] in exclude_code:
            continue
        vars = ["findingDetails", "findingType", "issueCode", "locations"]
        for v in vars:
            print(f"\t{v}: {find[v]}")
        print("\t---")

    cnt = cnt + 1
    if cnt > LIMIT:
        break


validate_policy メソッドのコール時に PpolicyTypeIDENTITY_POLICY を指定して、「IDベースのポリシーである」前提でチェックしています。

また、 exclude_code のところで、 REDUNDANT_STATEMENT , EMPTY_SID_VALUE を指定し、このエラーコードは無視するよう設定しています。

適宜カスタマイズしてご利用ください。

実行方法

$ python validate_policy.py


動作例

arn:aws:iam::xxxxxxxxxxx:policy/lambda-readwrite-policy
        findingDetails: アクション evenmts:DeauthorizeConnection で指定されたサービスは存在しません。
        findingType: ERROR
        issueCode: INVALID_SERVICE_IN_ACTION
        locations: [{'path': [{'value': 'Statement'}, {'index': 1}, {'value': 'Action'}, {'index': 12}], 'span': {'end': {'column': 386, 'line': 1, 'offset': 386}, 'start': {'column': 355, 'line': 1, 'offset': 355}}}]
        ---
arn:aws:iam::xxxxxxxxxxx:policy/rds-auto-start-lambda-policy
arn:aws:iam::xxxxxxxxxxx:policy/rds-auto-stop-lambda-policy
arn:aws:iam::xxxxxxxxxxx:policy/rds-kms-access-policy
        findingDetails: アクション kms:ReEncrypt は存在しません。 kms:ReEncryptFrom と kms:ReEncryptTo を意味しましたか? ReEncrypt と呼ばれる API は、ソースキーの kms:ReEncryptFrom とターゲットキーの kms:ReEncryptTo の両方に対して認証を行います。API を正常に呼び出すには、呼び出し元に両方が必要です。
        findingType: ERROR
        issueCode: INVALID_ACTION
        locations: [{'path': [{'value': 'Statement'}, {'index': 0}, {'value': 'Action'}, {'index': 0}], 'span': {'end': {'column': 42, 'line': 1, 'offset': 42}, 'start': {'column': 27, 'line': 1, 'offset': 27}}}]
        ---
arn:aws:iam::xxxxxxxxxxx:policy/rds-readonly-policy

エラーがあれば、その内容が表示されます。