IAM Policy SimulatorのAPIを使用して権限テストの自動化

# はじめに
作成したIAMポリシーをマネジメントコンソールから手動でテストするのは大変なので、APIを利用してテストの自動化をしてみました。

# 内容
AWS CLI、またはAWS SDKを使用して[IAM Policy Simulator](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/access_policies_testing-policies.html)を呼び出して、既存のIAMポリシーをプログラムでテストします。これにより、ポリシーが意図した効果を持っていることを確認します。

# IAM ポリシーをシミュレートするには
[SimulateCustomPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_SimulateCustomPolicy.html) および [SimulatePrincipalPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_SimulatePrincipalPolicy.html) のAPIを使います。AWS CLIとSDK（boto3）の以下のコマンドから上記のAPIを呼び出します。

## AWS CLI
- [simulate-custom-policy](https://docs.aws.amazon.com/cli/latest/reference/iam/simulate-custom-policy.html)
- [simulate-principal-policy](https://docs.aws.amazon.com/cli/latest/reference/iam/simulate-principal-policy.html)


## SDK (boto3)
- [simulate_custom_policy()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.simulate_custom_policy)
- [simulate_principal_policy()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.simulate_principal_policy)

# 説明
## SimulatePrincipalPolicy
IAM ユーザー、グループ、またはロールにアタッチされている既存のポリシーに対してアクセス許可の評価を行う場合に使用します。

## SimulateCustomPolicy
ポリシーに対してアクセス許可の評価を行う場合に使用します。

# 戻り値の例
```
{
    "EvaluationResults": [
        {
            "EvalActionName": "iam:ListUsers",
            "EvalResourceName": "arn:aws:iam::111111111111:user/",
            "EvalDecision": "allowed",
            "MatchedStatements": [
                {
                    "SourcePolicyId": "PolicyInputList.1",
                    "SourcePolicyType": "IAM Policy",
                    "StartPosition": {
                        "Line": 3,
                        "Column": 19
                    },
                    "EndPosition": {
                        "Line": 8,
                        "Column": 10
                    }
                }
            ],
            "MissingContextValues": []
        }
    ]
}
```

- EvalActionName : 評価対象のアクション名
- EvalDecision : 評価結果
    - allowed : アクションを許可
    - explicitDeny : アクションを明示的に拒否
    - implicitDeny : アクションを暗黙的に拒否

# 試してみる
今回はIAMポリシーに対してアクセス許可の確認をしたいので、SimulateCustomPolicyを使用します。
ポリシードキュメントを取得するために、下記のIAMアクションも使用しています。

- 管理ポリシーの内容を取得する	-	iam:GetPolicyVersion

# オプション
SimulateCustomPolicyで指定が必要なオプションは、以下の3つです。

- policy-input-list：ポリシードキュメントを指定するJSONファイル。テストしたいIAMポリシーのリストを含みます。

- action-names：テストしたいアクションのリスト。IAMポリシーのリストで指定されたポリシーをテストする際に使用されます。

- context-entries：オプション。シミュレートされるリクエストに関するコンテキスト情報のリスト。IAMポリシーで指定された条件式に使用されます。このオプションはポリシーに条件式が含まれている場合にのみ必要です。

## テストの流れ

① テストしたいIAMポリシーのポリシードキュメントを取得
② Policy Simulatorに「①で取得したポリシードキュメント」「評価対象のアクション」を投げる
③ Policy Simulatorが「許可」「拒否」のいずれかを返すので、期待通りかチェック

# CLIの例
CloudShellからスクリプトをアップロードして実行します。
評価対象のアクション名は"iam:ListUsers"を指定しています。

```Shell
#!/bin/bash

# 評価対象のポリシーのARN
POLICY_ARN=arn:aws:iam::111111111111:policy/ポリシー名

# ポリシードキュメントを取得
POLICY_DOCUMENT=$(aws iam get-policy-version --version-id "v13" --policy-arn "$POLICY_ARN" --query 'PolicyVersion.Document')
echo "POLICY_DOCUMENT : ${POLICY_DOCUMENT}"

# 評価対象アクション名に対する評価結果を取得
EVAL_DECISION=$(aws iam simulate-custom-policy --policy-input-list "${POLICY_DOCUMENT}" --action-names "iam:ListUsers" --query "EvaluationResults[].[EvalDecision]" --output text)
echo "EVAL_DECISION : ${EVAL_DECISION}"
```

評価対象アクション名に対する評価結果を出力するようにしており、下記のいずれかの値が出力されます。
* allowed : アクションを許可
* explicitDeny : アクションを明示的に拒否
* implicitDeny : アクションを暗黙的に拒否

# SDKの例
Lambdaから実行する場合は、[ドキュメント](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_iam_policy-sim.html)に記載の通り、下記の権限をLambdaロールに付与する必要があります。

```
"iam:GetContextKeysForCustomPolicy",
"iam:GetContextKeysForPrincipalPolicy",
"iam:SimulateCustomPolicy",
"iam:SimulatePrincipalPolicy"
"iam:GetPolicyVersion"　# ポリシードキュメントを取得するために追加
```

## コード
```Python
import boto3
import json

def lambda_handler(event, context):
    client = boto3.client('iam')

    # 評価対象のポリシーのARN
    policy_arn = "arn:aws:iam::111111111111:policy/ポリシー名"

    # ポリシードキュメントを取得
    dict_policy_documents = client.get_policy_version(
        PolicyArn = policy_arn,
        VersionId = v13
    )["PolicyVersion"]["Document"]

    # 辞書(dict)から文字列(str)へ変換
    str_policy_documents = json.dumps(dict_policy_documents)

    # 評価対象アクション名に対する評価結果を取得
    evaluation_results = client.simulate_custom_policy(
        PolicyInputList=[
            str_policy_documents
        ],
        ActionNames=[
            # 評価対象のアクション名
            'iam:ListUsers',
        ]
    )
    eval_decision = evaluation_results["EvaluationResults"][0]["EvalDecision"]
    print(eval_decision)
```

# 参考: iamアクションの一覧
- [CLI](https://docs.aws.amazon.com/cli/latest/reference/iam/)
- [SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#iam)