AWS Aurora PostgreSQLにTimezoneをCDKで明示的に指定したメモ

## 概要
RDSをCDKで作成するときに、timezoneを明示的に指定できるかを試してみる。
[aws-cdkでVPCを作ってRDSと踏み台サーバを設定したメモ](https://qiita.com/hibohiboo/items/9a6f6cf4b01927f670d0)を元に、下記Stackを作成。
前回はPostgresql11しかRDSProxyが対応していなかったが、現在は14を使用できるようになっている。
カスタムパラメータグループを使用して設定した。

[変更コミット](https://github.com/hibohiboo/aws-cdk-v2/commit/aa137a4d32b840723f307f90115057a504179207)

## コード

```diff
import { Aspects, RemovalPolicy, Stack, StackProps, Tag, Tags } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { InstanceClass, InstanceSize, InstanceType, SecurityGroup, SubnetType, Vpc } from 'aws-cdk-lib/aws-ec2';
import { AuroraPostgresEngineVersion, CfnDBProxyEndpoint, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseProxy, DatabaseSecret, ParameterGroup, ProxyTarget, SubnetGroup } from 'aws-cdk-lib/aws-rds';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
import { AccountPrincipal, Role } from 'aws-cdk-lib/aws-iam';
import { StringListParameter, StringParameter } from 'aws-cdk-lib/aws-ssm';

interface AuroraStackProps extends StackProps {
  vpcId: string
  sgId: string
  subnetGroupName: string
  dbAdminName: string
  dbAdminSecretName: string
  dbReadOnlyUserName: string
  dbReadOnlyUserSecretName: string
  ssmParamKeySubnetIds: string
}

export class AuroraStack extends Stack {
  constructor(scope: Construct, id: string, props: AuroraStackProps) {
    const superProps = {
      ...props, vpcId: undefined, sgId: undefined, subnetName: undefined
      , dbSecretName: undefined, dbAdminName: undefined, dbUserPassword: undefined

    } as StackProps
    super(scope, id, superProps);

    const vpc = Vpc.fromLookup(this, 'Vpc', { vpcId: props.vpcId })
    const securityGroup = SecurityGroup.fromLookupById(this, 'SecurityGroup', props.sgId);

    // subnetGroupNameはlowecaseで作成されている
    const subnetGroup = SubnetGroup.fromSubnetGroupName(this, 'SubnetGroup', props.subnetGroupName.toLowerCase());

    const secret = this.createSecret({ secretName: props.dbAdminSecretName, rdsName: props.dbAdminName });
    const engine = DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_14_7 });
    const cluster = new DatabaseCluster(this, 'clusterForAurora', {
      engine,
      removalPolicy: RemovalPolicy.DESTROY,
      defaultDatabaseName: 'postgres',

      instanceProps: {
        vpc,
        securityGroups: [securityGroup],
        instanceType: InstanceType.of(InstanceClass.T4G, InstanceSize.MEDIUM),
      },
      instances: 2,
      subnetGroup,
      parameterGroup: new ParameterGroup(this, 'rds params', {
        engine,
        description: 'Cluster Parameter Group for RDS',
        parameters: {
          log_rotation_age: '30', // デフォルト60分。
+          timezone: 'UTC', // 日本のTimezoneにするなら'Asia/Tokyo'
        },
      }),
      credentials: Credentials.fromSecret(secret)
    });

    // RDSでの作成ユーザをシークレットに登録
    const secretForDBUser = this.createSecret({ secretName: props.dbReadOnlyUserSecretName, rdsName: props.dbReadOnlyUserName });

    const proxy = cluster.addProxy('Proxy', {
      secrets: [cluster.secret!, secretForDBUser],
      vpc,
      securityGroups: [securityGroup],
      requireTLS: true,
      iamAuth: true
    });
    Tags.of(proxy).add('Name', 'AuroraRDSProxy');

    const role = new Role(this, 'DBProxyRole', { assumedBy: new AccountPrincipal(this.account) });
    Tags.of(role).add('Name', 'AuroraProxyRole');
    proxy.grantConnect(role, props.dbAdminName);
    proxy.grantConnect(role, props.dbReadOnlyUserName);

    // 読取専用エンドポイント
    const readOnlyEndpoint = new CfnDBProxyEndpoint(this, 'readOnlyProxyEndpoint', {
      dbProxyEndpointName: 'readOnlyProxyEndpoint',
      dbProxyName: proxy.dbProxyName,
      vpcSubnetIds: StringParameter.valueFromLookup(this, props.ssmParamKeySubnetIds).split(','), 
      targetRole: 'READ_ONLY',
      vpcSecurityGroupIds: [props.sgId]
    })
    Tags.of(readOnlyEndpoint).add('Name', 'readOnlyProxyEndpoint');

    // 作成したリソース全てにタグをつける
    Aspects.of(this).add(new Tag('Stack', id));
  }

  private createSecret(props: { secretName: string, rdsName: string }) {
    const secret = new DatabaseSecret(this, props.secretName, {
      secretName: props.secretName,
      username: props.rdsName
    });
    Tags.of(secret).add('Name', props.secretName);
    return secret;
  }
}

```

## 設定結果確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/a361620b-5cb3-97f8-71a9-12fe3ee2385e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/588c72aa-fa3f-744a-085e-d10a3863c33a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/566b187c-de9a-afd0-a0b8-319096319d74.png)

## 参考
[RDS for PostgreSQL DB インスタンスでのパラメータの使用](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Parameters.html)
[RDSProxyでPostgresql 14 をサポート開始](https://aws.amazon.com/jp/about-aws/whats-new/2022/12/amazon-rds-proxy-supports-postgresql-major-version-14/)
[MySQLの例](https://qiita.com/r-hirakawa/items/c71ead3e51307f3710b8)