CDKによるCognitoの作成方法について

### まず初めに

主にjavaとPHPをメインにプログラミングをしている一般人です。
自身初めてCDKを用いて設計・実装しています。(勉強中の為誤っている場合は教えていただきますと幸いです。)
少しでも誰かの役に立てば幸いです。

### 対象者
- AWSを学び始めた人
- CDKを学び始めた人
- CDKを用いてCognitoを利用したい人


### まず最初にCDKとは？
> AWS Cloud Development Kit (AWS CDK) は、使い慣れたプログラミング言語を使用してクラウドアプリケーションリソースを定義するためのオープンソースのソフトウェア開発フレームワークです。

とあるように、JavaScript、TypeScript、Python、Java、C#等で記述することが可能です。
開発環境の複製も簡単にできるというメリットもあります。

[詳しくはこちら](https://aws.amazon.com/jp/cdk/faqs/)

### 次にCognitoとは？
> Amazon Cognito は、ウェブおよびモバイルアプリの認証、承認、およびユーザー管理機能を提供します。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google、Apple などのサードパーティーを通じてサインインできます。

とあるように、AWSの他のサービスに対するアクセスなどの認証認可を精査します。

[詳しくはこちら](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/what-is-amazon-cognito.html)


### 環境設定
こちらを参考に環境設定を行います。

https://aws.amazon.com/jp/getting-started/guides/setup-cdk/

### CDKによるCognito作成
最小単位でロールバックができるようにある程度の粒度でスタックを切り分けています。
今回だとCognitoのみ作成します。
CfnXXX系を使用してCognitoを作成します。
(CDKが提供しているCognitotメソッドよりもより細かい粒度で設定できる為今回はCfnXXX系を使用しています。)


設定項目についてはピックアップしてコメントで記載します。
設定にあたり必須項目ではないものも含みますのでご了承ください。

```Typescript
import { Construct } from 'constructs';
import * as cognito from 'aws-cdk-lib/aws-cognito';
import { Env } from './env';
import {CfnOutput, RemovalPolicy, Stack, StackProps} from 'aws-cdk-lib';

export class CognitoStack extends Stack {

    private readonly removalPolicy: RemovalPolicy;
    public readonly userPool: cognito.CfnUserPool;
    public readonly  userPoolClient: cognito.CfnUserPoolClient;


    constructor(scope: Construct, id: string, props: Props) {
        super(scope, id, props);

        // Envファイルにて環境を設定しておくと便利です
        this.removalPolicy = props.stackEnv == Env.STAGE ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY
        
        // cfnUserPoolの作成
        this.userPool = new cognito.CfnUserPool(this, 'my-user-pool', {
            userPoolName: `my-user-pool`,
            adminCreateUserConfig: {
                allowAdminCreateUserOnly: true,
                // サインインしていない新しいアカウントが使用できなくなるまでのユーザーアカウントの有効期限
                unusedAccountValidityDays: 30
            },
            // 今回はサンプルの為OFFで設定していますが、セキュリティ要件に応じて適切に設定してください
            mfaConfiguration: 'OFF',
            // User名の大文字、小文字を区別するように変更
            usernameConfiguration: {
                caseSensitive: true
            },
            policies: {
                passwordPolicy: {
                    // 設定するパスワードのポリシーの設定
                    minimumLength: 10,
                    requireNumbers: true,
                    requireSymbols: false
                }
            },
            // アカウント復旧の設定
            accountRecoverySetting: {
                recoveryMechanisms: [{
                    // 管理者のみが復旧できるように設定
                    name: 'admin_only',
                    priority: 1
                }]
            },
        });
        // リソースのアップデートタイミングで前のバージョンを残すように設定
        this.userPool.applyRemovalPolicy(this.removalPolicy);

        // cfnUserPoolClientの作成
        this.userPoolClient = new cognito.CfnUserPoolClient(this, 'my-user-pool-client', {
            // 上記で作成したUserPoolと連携
            userPoolId: this.userPool.ref,
            clientName: `my-user-pool-client`,
            generateSecret: false,
            // OAuth プロトコルの設定(OAuthを用いた認証を許可しない)
            allowedOAuthFlowsUserPoolClient: false,
            // 認証フローについての設定
            explicitAuthFlows: ['ALLOW_ADMIN_USER_PASSWORD_AUTH', 'ALLOW_USER_PASSWORD_AUTH', 'ALLOW_REFRESH_TOKEN_AUTH'],
            // ユーザーの存在に関連するエラー設定
            preventUserExistenceErrors: 'ENABLED',
            // 各トークンの時間制限設定
            accessTokenValidity: 10,
            refreshTokenValidity: 20,
            idTokenValidity: 10,
            tokenValidityUnits: {
                accessToken: 'minutes',
                refreshToken: 'minutes',
                idToken: 'minutes'
            },
            // カスタム属性の設定
            readAttributes: ['name'],
            writeAttributes: ['name'],
        });
        this.userPoolClient.applyRemovalPolicy(this.removalPolicy);

        // 外部参照させたいパラメータをエクスポートする設定
        new CfnOutput(this, 'userPoolArnOutput', {
            value: this.userPool.attrArn,
            exportName: `${props.stackEnv}UserPoolArn`,
        });
    }
}

```
### 作成時に気をつけた点
- リソースの作成・更新・削除に関連する設定です。デフォルトとして削除になっているので注意して設定したいですね。
- applyRemovalPolicy
    - 削除に関するポリシーを設定します。(デフォルトで削除されないリソースもあるので注意が必要です。)
    - RemovalPolicy.RETAIN 
        - リソースやコンテンツを削除せず保持されます。
    - RemovalPolicy.DESTROY
        - デフォルト値：リソースが削除されると、物理的に削除されます。