AWS CDK CloudFormationExecutionRole

AWS CDKのworkshopで提供された一般権限ユーザを用いて管理者権限を持つユーザを作成できたため、その原因について調査を行いました。
## 事象
- cdk --version
2.165.0 (build 00f70f1)

### 使用する一般ユーザの権限
- cdk bootstrapに必要な権限のみ
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:*",
                "ecr:*",
                "ssm:*",
                "s3:*",
                "iam:*"
            ],
            "Resource": "*"
        }
    ]
}
```

### Stack(python)
- ユーザを新規作成し、AdministratorAccess policyを付与
```python
from aws_cdk import (
    Stack,
    aws_iam as iam 
    ,SecretValue
)
from constructs import Construct

class HelloCdkStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        user = iam.User(self, "adminuser", password=SecretValue.unsafe_plain_text("......"))
        user.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AdministratorAccess'))
```

### deploy結果
- cdk bootstrap
- cdk deploy

AdministratorAccess policyが付与されたユーザを作成できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/df68cd62-0981-c85a-65ba-741eca521cbe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/8c4a6f51-d781-a30a-8b20-43b4499bc25b.png)


## 原因
cdk v2ではcdk bootstrapを実行する際に、cloudformation-execution-policiesを指定しないと、デフォルトでAdministratorAccess policyが使用されることです。
[ref-cli-cmd-bootstrap](https://docs.aws.amazon.com/cdk/v2/guide/ref-cli-cmd-bootstrap.html)
```
--cloudformation-execution-policies ARRAY

    The managed IAM policy ARNs that should be attached to the deployment role assumed by AWS CloudFormation during deployment of your stacks.

    By default, stacks are deployed with full administrator permissions using the AdministratorAccess policy.
```

### cdk bootstrap log
cdk bootstrapの実行ログに、以下の内容が出力されていました。

:::note warn
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
:::

### CloudFormationExecutionRole
bootstrapで作成したCloudFormationExecutionRoleを確認したところ、AdministratorAccess policyが付与されていることが分かりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/c896a765-ea09-8738-303f-e34f802a75b1.png)

![382418658-02ee424b-b828-45f8-9e5a-f0924d573c32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/b72ed04b-aea1-2075-6151-6401560f28cc.png)

要するに、cdk bootstrapを実行する際に、cloudformation-execution-policiesを指定しないと、cdk deploy時に利用されるCloudFormation execute roleがAdministratorAccess権限を持つことになります。

### cloudformation-execution-policies指定
- cloudformation-execution-policiesにAmazonS3FullAccessを指定
```
cdk bootstrap --cloudformation-execution-policies arn:aws:iam::aws:policy/AmazonS3FullAccess
```
AmazonS3FullAccessしか持っていないCloudFormationExecutionRoleが作成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/c896a765-ea09-8738-303f-e34f802a75b1.png)

![382419623-f6388800-04bf-4911-ba66-23dad1c82171-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470230/5112a951-c117-5874-7f59-fe1a298b0fb9.png)

- この状態で同様なstackを用いてcdk deployを実行
想定通りのAccessDeniedExceptionが発生しました。

```
cdk deploy
```
```
❌  HelloCdkStack failed: ValidationError: User: arn:aws:sts::xxx:assumed-role/cdk-hnb659fds-cfn-exec-role-xxx-ap-northeast-1/AWSCloudFormation is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:xxx:parameter/cdk-bootstrap/hnb659fds/version because no identity-based policy allows the ssm:GetParameters action (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: AccessDeniedException; Request ID: 496d7206-1db8-4812-b2e0-068b2b6afce0; Proxy: null)
Waiting for the debugger to disconnect...
```

## 対策
AWSがShared Responsibility Modelを主張しているので、AdministratorAccessがdefault値であることは今後も変わらないと思われます。
しかし、cdk経由で管理者としてやり放題になることを避けべきです。
実際に試していませんが、以下の対策でcdk bootstrapの権限を制御できるはずです。
- SCP設定
- AWS Config ruleを利用
  - roleにboundaryを強制
- Eventbridge + Lambda
  - roleの新規作成をtriggerとして、roleにboundaryを自動的に追加