Conditions: IsFailoverRegion: !Not - !Equals - !Ref 'PrimaryRegionName' - !Ref 'AWS::Region' IsPrimaryRegion: !Equals - !Ref 'PrimaryRegionName' - !Ref 'AWS::Region' Metadata: AWS::CloudFormation::Interface: ParameterGroups: [] ParameterLabels: {} Comments: '' CreatedBy: Carter Meyers (AWS) Description: This application deploys a Global RDS Aurora cluster. LastUpdated: February 20, 2023 Version: v1.09 Outputs: GlobalAppDbClusterIdentifier: Condition: '' Export: Name: !Join - '-' - - !Ref 'MainStackName' - GlobalAppDbClusterIdentifier Value: !Ref 'GlobalAppCluster' GlobalAppDbReaderDnsEndpoint: Condition: '' Value: !Join - '' - - app - .db.reader. - !Ref 'PublicFqdn' - .internal GlobalAppDbWriterDnsEndpoint: Condition: '' Value: !Join - '' - - app - .db.writer. - !Ref 'PublicFqdn' - .internal GlobalDemoDbClusterIdentifier: Condition: '' Export: Name: !Join - '-' - - !Ref 'MainStackName' - GlobalDemoDbClusterIdentifier Value: !Ref 'GlobalDemoCluster' GlobalDemoDbReaderDnsEndpoint: Condition: '' Value: !Join - '' - - demo - .db.reader. - !Ref 'PublicFqdn' - .internal GlobalDemoDbWriterDnsEndpoint: Condition: '' Value: !Join - '' - - demo - .db.writer. - !Ref 'PublicFqdn' - .internal RegionalAppDbAdminSecretArn: Condition: '' Export: Name: !Join - '-' - - !Ref 'MainStackName' - AppDbAdminSecretArn Value: !Ref 'AppDbAdminSecret' RegionalAppDbClusterArn: Condition: '' Value: !GetAtt 'PrimaryAppCluster.DBClusterArn' RegionalAppDbClusterIdentifier: Condition: '' Value: !Ref 'PrimaryAppCluster' RegionalAppDbClusterReaderEndpoint: Condition: '' Value: !GetAtt 'PrimaryAppCluster.ReadEndpoint.Address' RegionalAppDbClusterWriterEndpoint: Condition: '' Value: !GetAtt 'PrimaryAppCluster.Endpoint.Address' RegionalAppDbProxyArn: Condition: '' Value: !GetAtt 'AppDbProxy.DBProxyArn' RegionalAppDbProxyName: Condition: '' Value: !Ref 'AppDbProxy' RegionalAppDbProxyPort: Condition: '' Value: !GetAtt 'PrimaryAppCluster.Endpoint.Port' RegionalAppDbProxyReaderEndpoint: Condition: '' Value: !GetAtt 'AppDbProxyReaderEndpoint.Endpoint' RegionalAppDbProxyWriterEndpoint: Condition: '' Value: !GetAtt 'AppDbProxy.Endpoint' RegionalDemoDbAdminSecretArn: Condition: '' Export: Name: !Join - '-' - - !Ref 'MainStackName' - DemoDbAdminSecretArn Value: !Ref 'DemoDbAdminSecret' RegionalDemoDbClusterArn: Condition: '' Value: !GetAtt 'PrimaryDemoCluster.DBClusterArn' RegionalDemoDbClusterIdentifier: Condition: '' Value: !Ref 'PrimaryDemoCluster' RegionalDemoDbClusterReaderEndpoint: Condition: '' Value: !GetAtt 'PrimaryDemoCluster.ReadEndpoint.Address' RegionalDemoDbClusterWriterEndpoint: Condition: '' Value: !GetAtt 'PrimaryDemoCluster.Endpoint.Address' RegionalKmsKeyArn: Condition: '' Export: Name: !Join - '-' - - !Ref 'MainStackName' - RegionalKmsKeyArn Value: !If - IsPrimaryRegion - !GetAtt 'KMSKey.Arn' - !GetAtt 'KMSKeyReplica.Arn' Parameters: CodeDownloadUrl: Default: https://codeload.github.com/aws-samples/amazon-aurora-postgresql-fast-failover-demo/zip/refs/heads/main Description: The URL from which the supporting codebase can be downloaded. This codebase is used to deploy the demo dashboard. Type: String DatabaseAdminPassword: Description: The password to be used for the RDS Aurora admin account. NoEcho: true Type: String DatabaseAdminUsername: Description: The username to be used for the RDS Aurora admin account. Type: String FailoverDatabaseSubnetZoneACidr: Default: 10.10.10.0/24 Description: The CIDR range you wish to use for your primary database subnet. Type: String FailoverDatabaseSubnetZoneBCidr: Default: 10.10.13.0/24 Description: The CIDR range you wish to use for your failover database subnet. Type: String FailoverPrivateSubnetZoneACidr: Default: 10.10.9.0/24 Description: The CIDR range you wish to use for your primary private subnet. Type: String FailoverPrivateSubnetZoneBCidr: Default: 10.10.12.0/24 Description: The CIDR range you wish to use for your failover private subnet. Type: String FailoverPublicSubnetZoneACidr: Default: 10.10.8.0/24 Description: The CIDR range you wish to use for your primary public subnet. Type: String FailoverPublicSubnetZoneBCidr: Default: 10.10.11.0/24 Description: The CIDR range you wish to use for your failover public subnet. Type: String FailoverRegionName: Default: us-east-2 Description: The name of the failover region (e.g., us-east-1). You may choose any AWS Region that supports the required services. The primary and failover regions must be different. Type: String FailoverVpcCidr: Default: 10.10.8.0/21 Description: The CIDR range you wish to use for your VPC. Type: String MainStackName: Type: String PrimaryDatabaseSubnetZoneACidr: Default: 10.10.2.0/24 Description: The CIDR range you wish to use for your primary database subnet. Type: String PrimaryDatabaseSubnetZoneBCidr: Default: 10.10.5.0/24 Description: The CIDR range you wish to use for your failover database subnet. Type: String PrimaryPrivateSubnetZoneACidr: Default: 10.10.1.0/24 Description: The CIDR range you wish to use for your primary private subnet. Type: String PrimaryPrivateSubnetZoneBCidr: Default: 10.10.4.0/24 Description: The CIDR range you wish to use for your failover private subnet. Type: String PrimaryPublicSubnetZoneACidr: Default: 10.10.0.0/24 Description: The CIDR range you wish to use for your primary public subnet. Type: String PrimaryPublicSubnetZoneBCidr: Default: 10.10.3.0/24 Description: The CIDR range you wish to use for your failover public subnet. Type: String PrimaryRegionName: Default: us-east-1 Description: The name of the primary region (e.g., us-east-1). You may choose any AWS Region that supports the required services. The primary and failover regions must be different. Type: String PrimaryVpcCidr: Default: 10.10.0.0/21 Description: The CIDR range you wish to use for your VPC. Type: String PrivateHostedZoneId: Type: String PublicFqdn: Description: >- The FQDN to be used by this application (e.g., multi-region-aurora.example.com). An Amazon ACM Certificate will be issued for this FQDN and attached to an Amazon ALB. This FQDN should NOT have a DNS record currently defined in the corresponding Route 53 Hosted Zone. Type: String PublicHostedZoneId: Description: The ID of the public Route 53 Hosted Zone corresponding to the public Service FQDN. Type: String Resources: AppDatabasePreparerResource: Condition: IsPrimaryRegion DependsOn: - DatabasePreparerLogGroup - AppDbAdminSecret - PrimaryAppInstance1 - PrimaryAppInstance2 Properties: Properties: DatabaseIdentifier: App QueriesToExecute: - "\n CREATE SEQUENCE IF NOT EXISTS data_sequence start 1 increment 1;\n " - "\n CREATE TABLE IF NOT EXISTS dataserver (\n id integer not null primary key default nextval('data_sequence'),\n guid VARCHAR(255)\ \ NOT NULL,\n insertedon timestamp NOT NULL DEFAULT NOW(),\n migratedon timestamp NOT NULL DEFAULT NOW()\n );\n \ \ " ServiceToken: !GetAtt 'DatabasePreparer.Arn' Type: Custom::ExecuteQueriesAgainstDatabase Version: '1.0' Type: AWS::CloudFormation::CustomResource AppDbAdminSecret: Properties: Description: !Join - '' - - 'Primary App DB Cluster Admin Account for ' - !Ref 'MainStackName' SecretString: !Join - '' - - '{"username": "' - !Ref 'DatabaseAdminUsername' - '", "password": "' - !Ref 'DatabaseAdminPassword' - '", "database": "template1"}' Type: AWS::SecretsManager::Secret AppDbDnsDeleter: Condition: IsPrimaryRegion Properties: Properties: Fqdns: - '*' HostedZoneId: !Ref 'PrivateHostedZoneId' ServiceToken: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalDnsRecordDeleterArn}} Type: Custom::DeployLambdaLayer Version: '1.0' Type: AWS::CloudFormation::CustomResource AppDbDnsRecords: Condition: IsPrimaryRegion DeletionPolicy: Retain DependsOn: - AppDbProxy Properties: HostedZoneId: !Ref 'PrivateHostedZoneId' RecordSets: - Name: !Join - . - - app - db - cluster - reader - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryAppCluster.ReadEndpoint.Address' TTL: '1' Type: CNAME - Name: !Join - . - - app - db - reader - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'AppDbProxyReaderEndpoint.Endpoint' TTL: '1' Type: CNAME - Name: !Join - . - - app - db - cluster - writer - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryAppCluster.Endpoint.Address' TTL: '1' Type: CNAME - Name: !Join - . - - app - db - writer - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'AppDbProxy.Endpoint' TTL: '1' Type: CNAME Type: AWS::Route53::RecordSetGroup AppDbProxy: Properties: Auth: - SecretArn: !Ref 'AppDbAdminSecret' DBProxyName: !Ref 'PrimaryAppCluster' EngineFamily: POSTGRESQL RequireTLS: true RoleArn: !GetAtt 'DbProxyRole.Arn' VpcSecurityGroupIds: - !Ref 'DbProxySecurityGroup' VpcSubnetIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /DatabaseSubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /DatabaseSubnetZoneBId}} Type: AWS::RDS::DBProxy AppDbProxyReaderEndpoint: DependsOn: - AppDbProxy Properties: DBProxyEndpointName: !Join - '-' - - !Ref 'MainStackName' - app - reader DBProxyName: !Ref 'AppDbProxy' TargetRole: READ_ONLY VpcSecurityGroupIds: - !Ref 'DbProxySecurityGroup' VpcSubnetIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /DatabaseSubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /DatabaseSubnetZoneBId}} Type: AWS::RDS::DBProxyEndpoint AppDbProxyTargetGroup: Condition: IsPrimaryRegion DependsOn: - AppDbProxy - PrimaryAppInstance1 Properties: DBClusterIdentifiers: - !Ref 'PrimaryAppCluster' DBProxyName: !Ref 'AppDbProxy' TargetGroupName: default Type: AWS::RDS::DBProxyTargetGroup AppDbSubnetGroup: Properties: DBSubnetGroupDescription: App Database Subnets DBSubnetGroupName: !Join - '' - - !Ref 'AWS::StackName' - !Join - '' - !Split - subnet- - !Join - '-' - - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Database - SubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Database - SubnetZoneAId}} SubnetIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Database - SubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Database - SubnetZoneBId}} Type: AWS::RDS::DBSubnetGroup ClusterParameterGroup: Properties: Description: !Join - '' - - !Ref 'AWS::StackName' - ' - Cluster Param Group' Family: aurora-postgresql13 Parameters: rds.logical_replication: 1 wal_sender_timeout: 240000 Type: AWS::RDS::DBClusterParameterGroup DatabasePreparer: Condition: IsPrimaryRegion DependsOn: - DatabasePreparerRole Properties: Architectures: - x86_64 Code: ZipFile: "import sys\nsys.path.append('/opt')\nimport subprocess\n\nimport os\nimport json\nimport boto3\nimport psycopg2\nimport cfnresponse\nimport multi_region_db\nfrom botocore.exceptions import\ \ ClientError as boto3_client_error\n\ncustom_functions = multi_region_db.Functions()\n\n'''\n RDSAdminSecretArn\n'''\ndef handler(event, context):\n \n print(json.dumps(event))\n \ \ \n if 'Properties' in event['ResourceProperties']:\n arguments = event['ResourceProperties']['Properties']\n \n operation = event['ResourceProperties']['Type'].replace('Custom::',\ \ '')\n \n response_data = {}\n \n if event['RequestType'] in ['Create', 'Update']:\n \n db_credentials = custom_functions.get_db_credentials(arguments['DatabaseIdentifier'])\n\ \ \n try:\n \n db_conn = psycopg2.connect(\n host = db_credentials['host'],\n port = db_credentials['port'],\n \ \ user = db_credentials['username'],\n password = db_credentials['password'],\n database = db_credentials['database'],\n connect_timeout = 3,\n\ \ sslmode = 'require',\n )\n \n curs = db_conn.cursor()\n \n for query in arguments['QueriesToExecute']:\n \ \ \n curs.execute(query.replace('\\r','').replace('\\n',' '))\n db_conn.commit()\n \n curs.close()\n db_conn.close()\n \n\ \ except Exception as error:\n\n print('There was a problem executing the DDL statements: ' + str(error))\n return cfnresponse.send(event, context, cfnresponse.FAILED,\ \ response_data)\n \n return cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)" Description: Executes DDL statements against new DB clusters to create necessary schema Environment: Variables: REGIONAL_APP_DB_SECRET_ARN: !Ref 'AppDbAdminSecret' REGIONAL_DEMO_DB_SECRET_ARN: !Ref 'DemoDbAdminSecret' Handler: index.handler Layers: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalLambdaLayerVersionArn}} MemorySize: 128 Role: !GetAtt 'DatabasePreparerRole.Arn' Runtime: python3.9 Timeout: 60 TracingConfig: Mode: PassThrough VpcConfig: SecurityGroupIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /LambdaSecurityGroupId}} SubnetIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /PrivateSubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /PrivateSubnetZoneBId}} Type: AWS::Lambda::Function DatabasePreparerLogGroup: Condition: IsPrimaryRegion DeletionPolicy: Delete DependsOn: - DatabasePreparer Properties: LogGroupName: !Join - '' - - /aws/lambda/ - !Ref 'DatabasePreparer' RetentionInDays: 30 Type: AWS::Logs::LogGroup DatabasePreparerRole: DependsOn: [] Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole MaxSessionDuration: 3600 Policies: - PolicyDocument: Statement: - Action: - secretsmanager:GetSecretValue Effect: Allow Resource: - !Ref 'AppDbAdminSecret' - !Ref 'DemoDbAdminSecret' Sid: GetRDSAdminSecret - Action: - kms:Decrypt Effect: Allow Resource: - !If - IsPrimaryRegion - !GetAtt 'KMSKey.Arn' - !GetAtt 'KMSKeyReplica.Arn' Sid: DecryptWithKMS PolicyName: database-secret-retrieval Type: AWS::IAM::Role DbClusterSecurityGroup: DependsOn: - DbProxySecurityGroup Properties: GroupDescription: RDS Security Group SecurityGroupEgress: [] SecurityGroupIngress: - Description: DB Access from In-Region Lambda Functions FromPort: 5432 IpProtocol: tcp SourceSecurityGroupId: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /LambdaSecurityGroupId}} ToPort: 5432 - Description: DB Access from In-Region RDS Proxy FromPort: 5432 IpProtocol: tcp SourceSecurityGroupId: !Ref 'DbProxySecurityGroup' ToPort: 5432 - CidrIp: !If - IsPrimaryRegion - !Ref 'FailoverPrivateSubnetZoneACidr' - !Ref 'PrimaryPrivateSubnetZoneACidr' Description: !Join - '' - - 'DB Access from Lambda Functions in ' - !If - IsPrimaryRegion - !Ref 'FailoverRegionName' - !Ref 'PrimaryRegionName' - a FromPort: 5432 IpProtocol: tcp ToPort: 5432 - CidrIp: !If - IsPrimaryRegion - !Ref 'FailoverPrivateSubnetZoneBCidr' - !Ref 'PrimaryPrivateSubnetZoneBCidr' Description: !Join - '' - - 'DB Access from Lambda Functions in ' - !If - IsPrimaryRegion - !Ref 'FailoverRegionName' - !Ref 'PrimaryRegionName' - b FromPort: 5432 IpProtocol: tcp ToPort: 5432 VpcId: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalVpcId}} Type: AWS::EC2::SecurityGroup DbProxyRole: DependsOn: - AppDbAdminSecret Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - rds.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess Policies: - PolicyDocument: Statement: - Action: - secretsmanager:GetSecretValue Effect: Allow Resource: - !Ref 'AppDbAdminSecret' PolicyName: main-policy Type: AWS::IAM::Role DbProxySecurityGroup: Properties: GroupDescription: RDS Proxy Security Group SecurityGroupEgress: [] SecurityGroupIngress: - Description: DB Access from Lambda FromPort: 5432 IpProtocol: tcp SourceSecurityGroupId: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /LambdaSecurityGroupId}} ToPort: 5432 - CidrIp: !If - IsPrimaryRegion - !Ref 'FailoverPrivateSubnetZoneACidr' - !Ref 'PrimaryPrivateSubnetZoneACidr' Description: !Join - '' - - 'DB Access from Lambda Functions in ' - !If - IsPrimaryRegion - !Ref 'FailoverRegionName' - !Ref 'PrimaryRegionName' - a FromPort: 5432 IpProtocol: tcp ToPort: 5432 - CidrIp: !If - IsPrimaryRegion - !Ref 'FailoverPrivateSubnetZoneBCidr' - !Ref 'PrimaryPrivateSubnetZoneBCidr' Description: !Join - '' - - 'DB Access from Lambda Functions in ' - !If - IsPrimaryRegion - !Ref 'FailoverRegionName' - !Ref 'PrimaryRegionName' - b FromPort: 5432 IpProtocol: tcp ToPort: 5432 VpcId: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalVpcId}} Type: AWS::EC2::SecurityGroup DemoDatabasePreparerResource: Condition: IsPrimaryRegion DependsOn: - DatabasePreparerLogGroup - DemoDbAdminSecret - PrimaryDemoInstance1 - PrimaryDemoInstance2 Properties: Properties: DatabaseIdentifier: Demo QueriesToExecute: - "\n CREATE TABLE IF NOT EXISTS dataclient (\n guid character varying(255) COLLATE pg_catalog.\"default\" NOT NULL,\n primary_region\ \ integer NOT NULL,\n failover_region integer NOT NULL,\n http_code integer,\n insertedon time without time zone\n \ \ );\n " - "\n CREATE TABLE IF NOT EXISTS failoverevents (\n event integer NOT NULL,\n insertedon timestamp without time zone NOT NULL\n\ \ );\n " ServiceToken: !GetAtt 'DatabasePreparer.Arn' Type: Custom::ExecuteQueriesAgainstDatabase Version: '1.0' Type: AWS::CloudFormation::CustomResource DemoDbAdminSecret: Properties: Description: !Join - '' - - 'Primary Demo DB Cluster Admin Account for ' - !Ref 'MainStackName' ReplicaRegions: - Region: !Ref 'FailoverRegionName' SecretString: !Join - '' - - '{"username": "' - !Ref 'DatabaseAdminUsername' - '", "password": "' - !Ref 'DatabaseAdminPassword' - '", "database": "template1"}' Type: AWS::SecretsManager::Secret DemoDbDnsDeleter: Condition: IsPrimaryRegion Properties: Properties: Fqdns: - '*' HostedZoneId: !Ref 'PrivateHostedZoneId' ServiceToken: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalDnsRecordDeleterArn}} Type: Custom::DeployLambdaLayer Version: '1.0' Type: AWS::CloudFormation::CustomResource DemoDbDnsRecords: Condition: IsPrimaryRegion DeletionPolicy: Retain DependsOn: [] Properties: HostedZoneId: !Ref 'PrivateHostedZoneId' RecordSets: - Name: !Join - . - - demo - db - cluster - reader - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryDemoCluster.ReadEndpoint.Address' TTL: '1' Type: CNAME - Name: !Join - . - - demo - db - reader - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryDemoCluster.ReadEndpoint.Address' TTL: '1' Type: CNAME - Name: !Join - . - - demo - db - cluster - writer - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryDemoCluster.Endpoint.Address' TTL: '1' Type: CNAME - Name: !Join - . - - demo - db - writer - !Ref 'PublicFqdn' - internal ResourceRecords: - !GetAtt 'PrimaryDemoCluster.Endpoint.Address' TTL: '1' Type: CNAME Type: AWS::Route53::RecordSetGroup DemoDbSubnetGroup: Properties: DBSubnetGroupDescription: Demo Database Subnets DBSubnetGroupName: !Join - '' - - !Ref 'AWS::StackName' - !Join - '' - !Split - subnet- - !Join - '-' - - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Private - SubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Private - SubnetZoneAId}} SubnetIds: - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Private - SubnetZoneAId}} - !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - / - Private - SubnetZoneBId}} Type: AWS::RDS::DBSubnetGroup GlobalAppCluster: Condition: IsPrimaryRegion DependsOn: - AppDbSubnetGroup - PrimaryAppCluster Properties: DeletionProtection: false SourceDBClusterIdentifier: !Ref 'PrimaryAppCluster' Type: AWS::RDS::GlobalCluster GlobalAppDbClusterIdentifierParam: Condition: '' Properties: Description: !Join - '' - - 'Global App DB Cluster Identifier for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalAppDbClusterIdentifier Tier: Standard Type: String Value: !Ref 'GlobalAppCluster' Type: AWS::SSM::Parameter GlobalAppDbReaderDnsEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Global DNS Endpoint for App DB Reader for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalAppDbReaderDnsEndpoint Tier: Standard Type: String Value: !Join - '' - - app - .db.reader. - !Ref 'PublicFqdn' - .internal Type: AWS::SSM::Parameter GlobalAppDbWriterDnsEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Global DNS Endpoint for App DB Writer for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalAppDbWriterDnsEndpoint Tier: Standard Type: String Value: !Join - '' - - app - .db.writer. - !Ref 'PublicFqdn' - .internal Type: AWS::SSM::Parameter GlobalDemoCluster: Condition: IsPrimaryRegion DependsOn: - DemoDbSubnetGroup - PrimaryDemoCluster Properties: DeletionProtection: false SourceDBClusterIdentifier: !Ref 'PrimaryDemoCluster' Type: AWS::RDS::GlobalCluster GlobalDemoDbClusterIdentifierParam: Condition: '' Properties: Description: !Join - '' - - 'Global Demo DB Cluster Identifier for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalDemoDbClusterIdentifier Tier: Standard Type: String Value: !Ref 'GlobalDemoCluster' Type: AWS::SSM::Parameter GlobalDemoDbReaderDnsEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Global DNS Endpoint for Demo DB Reader for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalDemoDbReaderDnsEndpoint Tier: Standard Type: String Value: !Join - '' - - demo - .db.reader. - !Ref 'PublicFqdn' - .internal Type: AWS::SSM::Parameter GlobalDemoDbWriterDnsEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Global DNS Endpoint for Demo DB Writer for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - GlobalDemoDbWriterDnsEndpoint Tier: Standard Type: String Value: !Join - '' - - demo - .db.writer. - !Ref 'PublicFqdn' - .internal Type: AWS::SSM::Parameter KMSKey: Condition: IsPrimaryRegion Properties: Description: !Join - '' - - 'Muli-Region KMS Key for ' - !Ref 'AWS::StackName' EnableKeyRotation: true Enabled: true KeyPolicy: Id: default-key-policy Statement: - Action: kms:* Effect: Allow Principal: AWS: !Join - '' - - 'arn:aws:iam::' - !Ref 'AWS::AccountId' - :root Resource: '*' Sid: Enable IAM User Permissions Version: '2012-10-17' MultiRegion: true Type: AWS::KMS::Key KMSKeyReplica: Condition: IsFailoverRegion Properties: Enabled: true KeyPolicy: Id: default-key-policy Statement: - Action: kms:* Effect: Allow Principal: AWS: !Join - '' - - 'arn:aws:iam::' - !Ref 'AWS::AccountId' - :root Resource: '*' Sid: Enable IAM User Permissions Version: '2012-10-17' PrimaryKeyArn: !GetAtt 'PrimaryRegionCmkRetriever.RegionalKmsKeyArn' Type: AWS::KMS::ReplicaKey PrimaryAppCluster: Condition: IsPrimaryRegion DeletionPolicy: Delete DependsOn: - AppDbSubnetGroup Properties: BackupRetentionPeriod: 30 DBSubnetGroupName: !Ref 'AppDbSubnetGroup' DeletionProtection: false EnableIAMDatabaseAuthentication: false Engine: aurora-postgresql EngineMode: provisioned EngineVersion: '13.7' KmsKeyId: !If - IsPrimaryRegion - !Ref 'KMSKey' - !Ref 'KMSKeyReplica' MasterUserPassword: !Ref 'DatabaseAdminPassword' MasterUsername: !Ref 'DatabaseAdminUsername' Port: 5432 StorageEncrypted: true VpcSecurityGroupIds: - !Ref 'DbClusterSecurityGroup' Type: AWS::RDS::DBCluster PrimaryAppDbAdminSecretAttachment: Condition: IsPrimaryRegion DependsOn: - AppDbAdminSecret - PrimaryAppCluster Properties: SecretId: !Ref 'AppDbAdminSecret' TargetId: !Ref 'PrimaryAppCluster' TargetType: AWS::RDS::DBCluster Type: AWS::SecretsManager::SecretTargetAttachment PrimaryAppInstance1: Condition: IsPrimaryRegion DependsOn: [] Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true DBClusterIdentifier: !Ref 'PrimaryAppCluster' DBInstanceClass: db.r6g.large EnablePerformanceInsights: false Engine: aurora-postgresql MultiAZ: false Type: AWS::RDS::DBInstance PrimaryAppInstance2: Condition: IsPrimaryRegion DependsOn: [] Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true DBClusterIdentifier: !Ref 'PrimaryAppCluster' DBInstanceClass: db.r6g.large EnablePerformanceInsights: false Engine: aurora-postgresql MultiAZ: false Type: AWS::RDS::DBInstance PrimaryDemoCluster: Condition: IsPrimaryRegion DeletionPolicy: Delete DependsOn: - DemoDbSubnetGroup Properties: BackupRetentionPeriod: 30 DBSubnetGroupName: !Ref 'DemoDbSubnetGroup' DeletionProtection: false EnableIAMDatabaseAuthentication: false Engine: aurora-postgresql EngineMode: provisioned EngineVersion: '13.7' KmsKeyId: !If - IsPrimaryRegion - !Ref 'KMSKey' - !Ref 'KMSKeyReplica' MasterUserPassword: !Ref 'DatabaseAdminPassword' MasterUsername: !Ref 'DatabaseAdminUsername' Port: 5432 StorageEncrypted: true VpcSecurityGroupIds: - !Ref 'DbClusterSecurityGroup' Type: AWS::RDS::DBCluster PrimaryDemoDbAdminSecretAttachment: Condition: IsPrimaryRegion DependsOn: - DemoDbAdminSecret - PrimaryDemoCluster Properties: SecretId: !Ref 'DemoDbAdminSecret' TargetId: !Ref 'PrimaryDemoCluster' TargetType: AWS::RDS::DBCluster Type: AWS::SecretsManager::SecretTargetAttachment PrimaryDemoInstance1: Condition: IsPrimaryRegion DependsOn: [] Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true DBClusterIdentifier: !Ref 'PrimaryDemoCluster' DBInstanceClass: db.r6g.large EnablePerformanceInsights: false Engine: aurora-postgresql MultiAZ: false Type: AWS::RDS::DBInstance PrimaryDemoInstance2: Condition: IsPrimaryRegion DependsOn: [] Properties: AllowMajorVersionUpgrade: false AutoMinorVersionUpgrade: true DBClusterIdentifier: !Ref 'PrimaryDemoCluster' DBInstanceClass: db.r6g.large EnablePerformanceInsights: false Engine: aurora-postgresql MultiAZ: false Type: AWS::RDS::DBInstance PrimaryRegionCmkRetriever: Condition: IsFailoverRegion Properties: Properties: ExportPrefix: !Ref 'MainStackName' Region: !Ref 'PrimaryRegionName' Version: 1.05 ServiceToken: !Join - '' - - '{{resolve:ssm:/' - !Ref 'MainStackName' - /RegionalCfnExportRetrieverArn}} Type: Custom::GetCFNExports Version: '1.0' Type: AWS::CloudFormation::CustomResource RegionalAppDbAdminSecretArnParam: Condition: '' Properties: Description: !Join - '' - - 'App DB Admin Secret ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbAdminSecretArn Tier: Standard Type: String Value: !Ref 'AppDbAdminSecret' Type: AWS::SSM::Parameter RegionalAppDbClusterArnParam: Condition: '' Properties: Description: !Join - '' - - 'Regional App DB Cluster ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbClusterArn Tier: Standard Type: String Value: !GetAtt 'PrimaryAppCluster.DBClusterArn' Type: AWS::SSM::Parameter RegionalAppDbClusterIdentifierParam: Condition: '' Properties: Description: !Join - '' - - 'Regional App DB Cluster Identifier for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbClusterIdentifier Tier: Standard Type: String Value: !Ref 'PrimaryAppCluster' Type: AWS::SSM::Parameter RegionalAppDbClusterReaderEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'App DB Cluster Reader Endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbClusterReaderEndpoint Tier: Standard Type: String Value: !GetAtt 'PrimaryAppCluster.ReadEndpoint.Address' Type: AWS::SSM::Parameter RegionalAppDbClusterWriterEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'App DB Cluster Writer Endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbClusterWriterEndpoint Tier: Standard Type: String Value: !GetAtt 'PrimaryAppCluster.Endpoint.Address' Type: AWS::SSM::Parameter RegionalAppDbProxyArnParam: Condition: '' Properties: Description: !Join - '' - - 'RDS Proxy ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbProxyArn Tier: Standard Type: String Value: !GetAtt 'AppDbProxy.DBProxyArn' Type: AWS::SSM::Parameter RegionalAppDbProxyNameParam: Condition: '' Properties: Description: !Join - '' - - 'App DB Proxy name for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbProxyName Tier: Standard Type: String Value: !Ref 'AppDbProxy' Type: AWS::SSM::Parameter RegionalAppDbProxyPortParam: Condition: '' Properties: Description: !Join - '' - - 'RDS Proxy port for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbProxyPort Tier: Standard Type: String Value: !GetAtt 'PrimaryAppCluster.Endpoint.Port' Type: AWS::SSM::Parameter RegionalAppDbProxyReaderEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'RDS Proxy reader endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbProxyReaderEndpoint Tier: Standard Type: String Value: !GetAtt 'AppDbProxyReaderEndpoint.Endpoint' Type: AWS::SSM::Parameter RegionalAppDbProxyWriterEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'RDS Proxy writer endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalAppDbProxyWriterEndpoint Tier: Standard Type: String Value: !GetAtt 'AppDbProxy.Endpoint' Type: AWS::SSM::Parameter RegionalDemoDbAdminSecretArnParam: Condition: '' Properties: Description: !Join - '' - - 'Demo DB Admin Secret ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalDemoDbAdminSecretArn Tier: Standard Type: String Value: !Ref 'DemoDbAdminSecret' Type: AWS::SSM::Parameter RegionalDemoDbClusterArnParam: Condition: '' Properties: Description: !Join - '' - - 'Regional Demo DB Cluster ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalDemoDbClusterArn Tier: Standard Type: String Value: !GetAtt 'PrimaryDemoCluster.DBClusterArn' Type: AWS::SSM::Parameter RegionalDemoDbClusterIdentifierParam: Condition: '' Properties: Description: !Join - '' - - 'Regional Demo DB Cluster Identifier for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalDemoDbClusterIdentifier Tier: Standard Type: String Value: !Ref 'PrimaryDemoCluster' Type: AWS::SSM::Parameter RegionalDemoDbClusterReaderEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Demo DB Cluster Reader Endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalDemoDbClusterReaderEndpoint Tier: Standard Type: String Value: !GetAtt 'PrimaryDemoCluster.ReadEndpoint.Address' Type: AWS::SSM::Parameter RegionalDemoDbClusterWriterEndpointParam: Condition: '' Properties: Description: !Join - '' - - 'Demo DB Cluster Writer Endpoint for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalDemoDbClusterWriterEndpoint Tier: Standard Type: String Value: !GetAtt 'PrimaryDemoCluster.Endpoint.Address' Type: AWS::SSM::Parameter RegionalKmsKeyArnParam: Condition: '' Properties: Description: !Join - '' - - 'Regional KMS Key ARN for ' - !Ref 'AWS::StackName' - ' stack' Name: !Join - '' - - / - !Ref 'MainStackName' - / - RegionalKmsKeyArn Tier: Standard Type: String Value: !If - IsPrimaryRegion - !GetAtt 'KMSKey.Arn' - !GetAtt 'KMSKeyReplica.Arn' Type: AWS::SSM::Parameter Transform: Name: AWS::SecretsManager-2020-07-23