AWSTemplateFormatVersion: '2010-09-09' Description: 'Cloudformation Template to create a VPC with public and private subnets in 3 AZs' Metadata: 'AWS::CloudFormation::Interface': ParameterGroups: - Label: default: 'VPC Parameters' Parameters: - ClassB - Label: default: Cloud9 Configuration Parameters: - C9InstanceType - Label: default: Deploy Aurora Parameters: - DeployAurora ParameterLabels: Application: default: Application Name ClassB: default: ClassB 2nd Octet C9InstanceType: default: Cloud9 Instance Type DeployAurora: default: Deploy Aurora PostgreSQL Cluster Parameters: Application: Description: 'Specify Application Name' Type: String Default: 'EKSAURGDB' ClassB: Description: 'Specify the 2nd Octet of IPv4 CIDR block for the VPC (10.XXX.0.0/16) in the range [0-255]' Type: Number Default: 40 ConstraintDescription: 'Must be in the range [0-255]' MinValue: 0 MaxValue: 255 C9InstanceType: AllowedValues: - t2.micro - t3.micro - t3.small - t3.medium Default: t3.medium Description: Amazon Cloud9 instance type Type: String DeployAurora: Description: Deploy Aurora PostgreSQL Cluster Type: String Default: yes AllowedValues: - yes - no DBClusterIdentifier: Description: Aurora Database Cluster Identifier Type: String MinLength: '1' MaxLength: '64' AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 64 characters Default: adbtest GlobalDBClusterIdentifier: Description: Aurora Database Global Cluster Identifier Type: String MinLength: '1' MaxLength: '64' AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 64 characters Default: agdbtest DBName: Description: Database Name Type: String MinLength: '1' MaxLength: '64' AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 64 characters Default: pgbench DBPort: Description: TCP/IP Port for the Database Instance Type: Number Default: 5432 ConstraintDescription: 'Must be in the range [1115-65535]' MinValue: 1115 MaxValue: 65535 DBUsername: Description: Database master username Type: String MinLength: '1' MaxLength: '16' AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_]*$" ConstraintDescription: Must start with a letter. Only numbers, letters, and _ accepted. max length 16 characters Default: postgres DBUserPassword: Description: Database master password Type: String NoEcho: true MinLength: '1' MaxLength: '41' Default: postgres AllowedPattern: "^[a-zA-Z0-9]*$" DBEngineVersion: Description: Select Database Engine Version Type: String Default: 13.9 AllowedValues: - 13.9 - 14.6 DBInstanceClass: Default: db.r5.large Description: Database Instance Class. db.r5 instance classes are supported for Aurora PostgreSQL 10.6 or later. db.t3.medium instance class is supported for Aurora PostgreSQL 10.7 or later. Type: String AllowedValues: - db.r5.large - db.r5.xlarge - db.r5.2xlarge - db.r5.4xlarge - db.r5.8xlarge - db.r5.12xlarge - db.r5.16xlarge - db.r5.24xlarge Conditions: createResource: !Equals [!Ref DeployAurora, true] Mappings: AWSAMIRegionMap: ap-northeast-1: AMZNLINUXHVM: ami-0318ecd6d05daa212 ap-northeast-2: AMZNLINUXHVM: ami-09391a0ad9f9243b6 ap-south-1: AMZNLINUXHVM: ami-04b2519c83e2a7ea5 ap-southeast-1: AMZNLINUXHVM: ami-0dff4318d85149d5d ap-southeast-2: AMZNLINUXHVM: ami-050e1ec030abb8dde ca-central-1: AMZNLINUXHVM: ami-021321e9bc16d5186 eu-central-1: AMZNLINUXHVM: ami-03ab4e8f1d88ce614 me-south-1: AMZNLINUXHVM: ami-02a841b5a224a1caf ap-east-1: AMZNLINUXHVM: ami-c86e28b9 eu-north-1: AMZNLINUXHVM: ami-0c5254b956817b326 eu-west-1: AMZNLINUXHVM: ami-00890f614e48ce866 eu-west-2: AMZNLINUXHVM: ami-0596aab74a1ce3983 eu-west-3: AMZNLINUXHVM: ami-06cba15121418cdcb sa-east-1: AMZNLINUXHVM: ami-03e1e4abf50e14ded us-east-1: AMZNLINUXHVM: ami-0915e09cc7ceee3ab us-gov-west-1: AMZNLINUXHVM: ami-f5e4d294 us-gov-east-1: AMZNLINUXHVM: ami-51ef0320 us-east-2: AMZNLINUXHVM: ami-097834fcb3081f51a us-west-1: AMZNLINUXHVM: ami-0027eed75be6f3bf4 us-west-2: AMZNLINUXHVM: ami-01f08ef3e76b957e5 cn-north-1: AMZNLINUXHVM: ami-04b1196830276cd1f cn-northwest-1: AMZNLINUXHVM: ami-0bae393f70322bed6 LinuxAMINameMap: Amazon-Linux-HVM: Code: AMZNLINUXHVM Resources: VPC: Type: 'AWS::EC2::VPC' Properties: CidrBlock: !Sub '10.${ClassB}.0.0/16' EnableDnsSupport: true EnableDnsHostnames: true InstanceTenancy: default Tags: - Key: Name Value: !Sub '${AWS::StackName}-vpc' InternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Name Value: !Sub '${AWS::StackName}-igw' VPCGatewayAttachment: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway SubnetAPublic: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Sub '10.${ClassB}.64.0/20' AvailabilityZone: !Select [0, !GetAZs ] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${AWS::StackName}-pub-sub-a - Key: kubernetes.io/role/elb Value: 1 SubnetBPublic: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Sub '10.${ClassB}.80.0/20' AvailabilityZone: !Select [1, !GetAZs ] MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${AWS::StackName}-pub-sub-b - Key: kubernetes.io/role/elb Value: 1 RouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-vpc-rt' RouteTablePublicInternetRoute: Type: 'AWS::EC2::Route' DependsOn: VPCGatewayAttachment Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetBPublic RouteTableId: !Ref RouteTable SubnetRouteTableBAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetAPublic RouteTableId: !Ref RouteTable natEip: Type: AWS::EC2::EIP Properties: Domain: vpc vpcNgw: Type: AWS::EC2::NatGateway DependsOn: VPCGatewayAttachment Properties: AllocationId: !GetAtt natEip.AllocationId SubnetId: !Ref SubnetAPublic SubnetAPrivate: Type: 'AWS::EC2::Subnet' Properties: AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Sub '10.${ClassB}.16.0/20' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-pvt-a - Key: kubernetes.io/role/internal-elb Value: 1 SubnetBPrivate: Type: 'AWS::EC2::Subnet' Properties: AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Sub '10.${ClassB}.32.0/20' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-pvt-b - Key: kubernetes.io/role/internal-elb Value: 1 SubnetCPrivate: Type: 'AWS::EC2::Subnet' Properties: AvailabilityZone: !Select [2, !GetAZs ''] CidrBlock: !Sub '10.${ClassB}.48.0/20' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-pvt-c - Key: kubernetes.io/role/internal-elb Value: 1 RouteTablePrivate: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-pvt-rt rteToNgw: Type: AWS::EC2::Route Properties: RouteTableId: !Ref RouteTablePrivate DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref vpcNgw RouteTableAssociationAPrivate: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetAPrivate RouteTableId: !Ref RouteTablePrivate RouteTableAssociationBPrivate: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetBPrivate RouteTableId: !Ref RouteTablePrivate RouteTableAssociationCPrivate: Type: 'AWS::EC2::SubnetRouteTableAssociation' Properties: SubnetId: !Ref SubnetCPrivate RouteTableId: !Ref RouteTablePrivate NetworkAclPublic: Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-nacl-pub NetworkAclEntryInPublicAllowVPC: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPublic RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: false CidrBlock: '0.0.0.0/0' NetworkAclEntryOutPublicAllowVPC: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPublic RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: true CidrBlock: '0.0.0.0/0' SubnetNetworkAclAssociationAPublic: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetAPublic NetworkAclId: !Ref NetworkAclPublic SubnetNetworkAclAssociationBPublic: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetBPublic NetworkAclId: !Ref NetworkAclPublic NetworkAclPrivate: Type: 'AWS::EC2::NetworkAcl' Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${AWS::StackName}-nacl-pvt SubnetNetworkAclAssociationAPrivate: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetAPrivate NetworkAclId: !Ref NetworkAclPrivate SubnetNetworkAclAssociationBPrivate: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetBPrivate NetworkAclId: !Ref NetworkAclPrivate SubnetNetworkAclAssociationCPrivate: Type: 'AWS::EC2::SubnetNetworkAclAssociation' Properties: SubnetId: !Ref SubnetCPrivate NetworkAclId: !Ref NetworkAclPrivate NetworkAclEntryInPrivateAllowVPC: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPrivate RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: false CidrBlock: '0.0.0.0/0' NetworkAclEntryOutPrivateAllowVPC: Type: 'AWS::EC2::NetworkAclEntry' Properties: NetworkAclId: !Ref NetworkAclPrivate RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: true CidrBlock: '0.0.0.0/0' SecretSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Join [ " - ", [ "Security group for Secrets Access ENIs", !Ref 'AWS::StackName' ] ] VpcId: !Ref VPC SecurityGroupEgress: - IpProtocol: -1 CidrIp: "0.0.0.0/0" SecurityGroupIngress: - IpProtocol: -1 CidrIp: !Sub '10.${ClassB}.0.0/16' Tags: - Key: Name Value: !Sub '${AWS::StackName}-SecretSecurityGroup' SecretsManagerVPCEndpoint: Type: 'AWS::EC2::VPCEndpoint' Properties: VpcEndpointType: 'Interface' PrivateDnsEnabled: true VpcId: !Ref VPC SubnetIds: - !Ref SubnetAPrivate - !Ref SubnetBPrivate - !Ref SubnetCPrivate SecurityGroupIds: - !Ref SecretSecurityGroup ServiceName: !Join - '' - - com.amazonaws. - !Ref 'AWS::Region' - .secretsmanager DBSubnetGroup: Type: 'AWS::RDS::DBSubnetGroup' Properties: DBSubnetGroupDescription: !Ref 'AWS::StackName' SubnetIds: - !Ref SubnetAPrivate - !Ref SubnetBPrivate - !Ref SubnetCPrivate ClusterSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: !Ref 'AWS::StackName' SecurityGroupEgress: - IpProtocol: -1 CidrIp: "0.0.0.0/0" SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref DBPort ToPort: !Ref DBPort CidrIp: !Sub '10.0.0.0/8' Description: 'Access to AppServer Host Security Group' VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-AuroraClusterSecurityGroup' ClusterSecurityGroupIngress: Type: 'AWS::EC2::SecurityGroupIngress' Properties: GroupId: !GetAtt 'ClusterSecurityGroup.GroupId' IpProtocol: -1 SourceSecurityGroupId: !Ref ClusterSecurityGroup Description: 'Self Reference' AuroraKMSCMK: Type: 'AWS::KMS::Key' DeletionPolicy: Retain Properties: EnableKeyRotation: true KeyPolicy: Version: '2012-10-17' Statement: - Effect: Allow Principal: AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' Action: 'kms:*' Resource: '*' - Effect: Allow Principal: "Service": - "s3.amazonaws.com" - "events.amazonaws.com" - "sqs.amazonaws.com" - "lambda.amazonaws.com" - "rds.amazonaws.com" Action: - 'kms:Encrypt' - 'kms:Decrypt' - 'kms:ReEncrypt*' - 'kms:GenerateDataKey*' - 'kms:CreateGrant' - 'kms:ListGrants' - 'kms:DescribeKey' Resource: - !Sub "arn:aws:kms:${AWS::Region}:${AWS::AccountId}:*" AuroraKMSCMKAlias: Condition: createResource Type: 'AWS::KMS::Alias' DeletionPolicy: Delete DependsOn: AuroraDBCluster Properties: AliasName: !Sub 'alias/${AuroraDBCluster}9' TargetKeyId: !Ref AuroraKMSCMK AuroraMasterSecret: Type: AWS::SecretsManager::Secret Properties: Name: !Join ['/', ['aurora-pg', !Ref 'AWS::StackName']] Description: !Join ['', ['Aurora PostgreSQL Master User Secret ', 'for CloudFormation Stack ', !Ref 'AWS::StackName']] Tags: - Key: DatabaseEngine Value: 'Aurora PostgreSQL' - Key: StackID Value: !Ref 'AWS::StackId' SecretString: !Sub '{"username": "${DBUsername}", "password": "${DBUserPassword}"}' SecretAuroraClusterAttachment: Condition: createResource Type: AWS::SecretsManager::SecretTargetAttachment Properties: SecretId: !Ref AuroraMasterSecret TargetId: !Ref AuroraDBCluster TargetType: AWS::RDS::DBCluster AuroraSecretResourcePolicy: Type: AWS::SecretsManager::ResourcePolicy Properties: SecretId: !Ref AuroraMasterSecret ResourcePolicy: Version: "2012-10-17" Statement: - Effect: "Deny" Principal: AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root" Action: "secretsmanager:DeleteSecret" Resource: "*" AuroraDBCluster: Condition: createResource Type: AWS::RDS::DBCluster DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: DBClusterIdentifier: !Ref DBClusterIdentifier Engine: aurora-postgresql EngineVersion: !Ref DBEngineVersion DatabaseName: !Ref DBName Port: !Ref DBPort MasterUsername: !Join ['', ['{{resolve:secretsmanager:', !Ref AuroraMasterSecret, ':SecretString:username}}' ]] MasterUserPassword: !Join ['', ['{{resolve:secretsmanager:', !Ref AuroraMasterSecret, ':SecretString:password}}' ]] DBSubnetGroupName: !Ref DBSubnetGroup VpcSecurityGroupIds: - !Ref ClusterSecurityGroup BackupRetentionPeriod: 1 StorageEncrypted: true KmsKeyId: !Ref AuroraKMSCMK EnableIAMDatabaseAuthentication: false Tags: - Key: Application Value: !Ref Application AuroraDBFirstInstance: Condition: createResource Type: AWS::RDS::DBInstance Properties: CopyTagsToSnapshot: true DBInstanceClass: Ref: DBInstanceClass DBClusterIdentifier: !Ref AuroraDBCluster Engine: aurora-postgresql EngineVersion: !Ref DBEngineVersion MonitoringInterval: 0 MonitoringRoleArn: !Ref "AWS::NoValue" AutoMinorVersionUpgrade: 'true' DBSubnetGroupName: !Ref DBSubnetGroup PubliclyAccessible: false EnablePerformanceInsights: true PerformanceInsightsKMSKeyId: !Ref AuroraKMSCMK PerformanceInsightsRetentionPeriod: 7 Tags: - Key: Application Value: !Ref Application AuroraGlobalDbCluster: Condition: createResource Type: AWS::RDS::GlobalCluster Properties: GlobalClusterIdentifier: !Ref GlobalDBClusterIdentifier SourceDBClusterIdentifier: !Ref AuroraDBCluster DeletionProtection: false #--------------------------------------------------------------------------------------- # Cloud 9 Setup #--------------------------------------------------------------------------------------- C9Role: Type: AWS::IAM::Role Properties: Tags: - Key: Environment Value: AuroraGlobal AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com - ssm.amazonaws.com - lambda.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess Path: "/" C9LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: Fn::Join: - '' - - C9LambdaPolicy- - Ref: AWS::Region PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* - Effect: Allow Action: - cloudformation:DescribeStacks - cloudformation:DescribeStackEvents - cloudformation:DescribeStackResource - cloudformation:DescribeStackResources - ec2:DescribeInstances - ec2:AssociateIamInstanceProfile - ec2:DescribeIamInstanceProfileAssociations - ec2:ModifyInstanceAttribute - ec2:ReplaceIamInstanceProfileAssociation - ec2:DisassociateIamInstanceProfile - iam:ListInstanceProfiles - iam:PassRole Resource: "*" C9BootstrapInstanceLambda: Description: Bootstrap Cloud9 instance Type: Custom::C9BootstrapInstanceLambda DependsOn: - C9BootstrapInstanceLambdaFunction - C9Instance - C9InstanceProfile - C9LambdaExecutionRole Properties: Tags: - Key: Environment Value: AuroraGlobal ServiceToken: Fn::GetAtt: - C9BootstrapInstanceLambdaFunction - Arn REGION: Ref: AWS::Region StackName: Ref: AWS::StackName EnvironmentId: Ref: C9Instance LabIdeInstanceProfileName: Ref: C9InstanceProfile LabIdeInstanceProfileArn: Fn::GetAtt: - C9InstanceProfile - Arn C9BootstrapInstanceLambdaFunction: Type: AWS::Lambda::Function Properties: Tags: - Key: Environment Value: AuroraGlobal Handler: index.lambda_handler Role: Fn::GetAtt: - C9LambdaExecutionRole - Arn Runtime: python3.9 MemorySize: 2056 Timeout: '600' Code: ZipFile: | from __future__ import print_function import boto3 import json import os import time import traceback import cfnresponse import logging def lambda_handler(event, context): print('event: {}'.format(event)) print('context: {}'.format(context)) responseData = {} if event.get('RequestType') != 'Create': responseData = {'Success': 'Skipping bootstrapping for non Create crud operation'} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID') if event['RequestType'] == 'Create': try: # Open AWS clients ec2 = boto3.client('ec2') # Get the InstanceId of the Cloud9 IDE instance = ec2.describe_instances(Filters=[{'Name': 'tag:Name','Values': ['aws-cloud9-'+event['ResourceProperties']['StackName']+'-'+event['ResourceProperties']['EnvironmentId']]}])['Reservations'][0]['Instances'][0] logging.info('instance: {}'.format(instance)) # Create the IamInstanceProfile request object iam_instance_profile = { 'Arn': event['ResourceProperties']['LabIdeInstanceProfileArn'], 'Name': event['ResourceProperties']['LabIdeInstanceProfileName'] } logging.info('iam_instance_profile: {}'.format(iam_instance_profile)) # Wait for Instance to become ready before adding Role instance_state = instance['State']['Name'] logging.info('instance_state: {}'.format(instance_state)) while instance_state != 'running': time.sleep(5) instance_state = ec2.describe_instances(InstanceIds=[instance['InstanceId']]) logging.info('instance_state: {}'.format(instance_state)) # deassociate existing profile response = ec2.describe_iam_instance_profile_associations(Filters = [ {'Name': 'instance-id', 'Values': [instance['InstanceId']] } ] ) for x in response.get('IamInstanceProfileAssociations',{}): if x.get('State') == 'associated': r = ec2.disassociate_iam_instance_profile(AssociationId= x.get('AssociationId')) # attach instance profile response = ec2.associate_iam_instance_profile(IamInstanceProfile=iam_instance_profile, InstanceId=instance['InstanceId']) logging.info('response - associate_iam_instance_profile: {}'.format(response)) r_ec2 = boto3.resource('ec2') responseData = {'Success': 'Started bootstrapping for instance: '+instance['InstanceId']} cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, 'CustomResourcePhysicalID') except Exception as e: logging.error(e, exc_info=True) responseData = {'Error': str(traceback.format_exc(e))} cfnresponse.send(event, context, cfnresponse.FAILED, responseData, 'CustomResourcePhysicalID') C9OutputBucket: Type: AWS::S3::Bucket DeletionPolicy: Delete C9Bootstrap: Type: AWS::SSM::Document Properties: Tags: - Key: Environment Value: AuroraGlobal Content: Yaml DocumentType: Command Content: schemaVersion: '2.2' description: Bootstrap cloud9 for installing redisclient and other required libraries mainSteps: - action: aws:runShellScript name: BootstrapTools inputs: runCommand: - "#!/bin/bash" - echo "Bootstrap completed with return code $?" C9BootstrapAssociation: Type: AWS::SSM::Association DependsOn: C9OutputBucket Properties: Name: !Ref C9Bootstrap OutputLocation: S3Location: OutputS3BucketName: !Ref C9OutputBucket OutputS3KeyPrefix: bootstrapoutput Targets: - Key: tag:SSMBootstrap Values: - Active C9InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: "/" Roles: - Ref: C9Role C9Instance: Description: "-" DependsOn: C9BootstrapAssociation Type: AWS::Cloud9::EnvironmentEC2 Properties: Name: !Sub '${AWS::StackName}' AutomaticStopTimeMinutes: 60 Description: AWS Cloud9 instance for AuroraGlobal InstanceType: !Ref C9InstanceType ImageId: amazonlinux-2-x86_64 SubnetId: !Ref SubnetAPublic Repositories: - RepositoryUrl: https://github.com/aws-samples/eks-aurora-global-database.git PathComponent: eks-aurora-global-database Tags: - Key: SSMBootstrap Value: Active - Key: Environment Value: AuroraGlobal ECRRepoWebapp: Description: "ECR Repository for Webapp" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/webapp" EncryptionConfiguration: EncryptionType: AES256 ECRRepoProduct: Description: "ECR Repository for Product" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/product" EncryptionConfiguration: EncryptionType: AES256 ECRRepoOrder: Description: "ECR Repository for Order" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/order" EncryptionConfiguration: EncryptionType: AES256 ECRRepoKart: Description: "ECR Repository for Kart" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/kart" EncryptionConfiguration: EncryptionType: AES256 ECRRepoUser: Description: "ECR Repository for User" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/user" EncryptionConfiguration: EncryptionType: AES256 ECRRepoPgBouncer: Description: "ECR Repository for PgBouncer" Type: AWS::ECR::Repository Properties: RepositoryName: "retailapp/pgbouncer" EncryptionConfiguration: EncryptionType: AES256 Outputs: TemplateID: Description: 'Template ID' Value: 'VPC-3AZs' Region: Description: 'Region' Value: '${AWS::Region}' StackName: Description: 'Stack name' Value: !Sub '${AWS::StackName}' VPC: Description: 'VPC' Value: !Ref VPC Export: Name: !Sub '${AWS::StackName}-VPC' SecretsManagerVPCEndpoint: Description: Secrets Manager VPC Endpoint Value: !Ref SecretsManagerVPCEndpoint Export: Name: !Sub '${AWS::StackName}-SecretsManagerVPCEndpoint' ClusterEndpoint: Condition: createResource Description: 'Aurora Cluster/Writer Endpoint' Value: !GetAtt 'AuroraDBCluster.Endpoint.Address' Export: Name: 'Fn::Sub': '${AWS::StackName}-AuroraClusterEndPoint' ClusterIdentifier: Condition: createResource Description: 'Aurora Cluster Identifier' Value: !Ref AuroraDBCluster Export: Name: 'Fn::Sub': '${AWS::StackName}-AuroraClusterIdentifier' GlobalClusterIdentifier: Condition: createResource Description: 'Aurora Global Cluster Identifier' Value: !Ref AuroraGlobalDbCluster Export: Name: 'Fn::Sub': '${AWS::StackName}-AuroraGlobalClusterIdentifier' DBUsername: Condition: createResource Description: 'Database master username' Value: !Ref DBUsername Export: Name: 'Fn::Sub': '${AWS::StackName}-DbUsername' DBName: Condition: createResource Description: 'Database Name' Value: !Ref DBName Export: Name: 'Fn::Sub': '${AWS::StackName}-DBName' DBEngineVersion: Condition: createResource Description: 'Database Engine Versino' Value: !Ref DBEngineVersion Export: Name: 'Fn::Sub': '${AWS::StackName}-DBEngineVersion' DBInstanceClass: Condition: createResource Description: 'Database Instance Class' Value: !Ref DBInstanceClass Export: Name: 'Fn::Sub': '${AWS::StackName}-DBInstanceClass' AuroraMasterSecret: Description: 'Aurora Secret' Value: !Ref AuroraMasterSecret Export: Name: 'Fn::Sub': '${AWS::StackName}-AuroraMasterSecret' AuroraKMSCMK: Description: 'Aurora KMS' Value: !Ref AuroraKMSCMK Export: Name: 'Fn::Sub': '${AWS::StackName}-AuroraKMSCMK' ClusterSecurityGroup: Description: 'Aurora ClusterSecurityGroup' Value: !Ref ClusterSecurityGroup Export: Name: 'Fn::Sub': '${AWS::StackName}-ClusterSecurityGroup' DBSubnetGroup: Description: 'DB Subnet Group' Value: !Ref DBSubnetGroup Export: Name: 'Fn::Sub': '${AWS::StackName}-DBSubnetGroup' Cloud9IDEURL: Export: Name: 'Fn::Sub': '${AWS::StackName}-Cloud9IDEURL' Value: !Join - '' - - !Sub https://${AWS::Region}.console.aws.amazon.com/cloud9/ide/ - !Ref C9Instance Cloud9Role: Condition: createResource Value: !Ref C9Role Export: Name: 'Fn::Sub': '${AWS::StackName}-Cloud9Role'