diff --git a/README.md b/README.md index 99387fcb..fa8a5bea 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ The StartupKit-templates repo contains a collection of AWS [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) templates intended to help you set up common pieces of AWS infrastructure. Each template defines a [stack](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html), which is a collection of related resources that can be created, updated, or deleted as a single unit. Templates are available for creating: - A secure network inside a [VPC](https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Introduction.html) ([jump](#vpc)) -- A [bastion host](https://en.wikipedia.org/wiki/Bastion_host) to securely access instances inside the VPC ([jump](#bastion-host)) +- AWS Session Manager to securely access inside the VPC ([jump](#aws-session-manager)) - A deployment environment using [AWS Elastic Beanstalk](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html) ([jump](#aws-elastic-beanstalk)) - A container-based environment using [AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_GetStarted.html) ([jump](#aws-fargate)) - A relational database using [Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Welcome.html) ([jump](#amazon-rds)) @@ -76,10 +76,14 @@ Security groups act as firewalls at the instance level, to control inbound and o -### Bastion Host +### AWS Session Manager It is preferable not to ssh into EC2 instances at all, instead monitoring instances by configuring them to send logs to [CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html) or other services, and managing instantiation, configuration, and termination of instances using devops tools. +Session Manager is a fully managed AWS Systems Manager capability that lets you manage your Amazon EC2 instances through an interactive one-click browser-based shell or through the AWS CLI. Session Manager provides secure and auditable instance management without the need to open inbound ports, maintain bastion hosts, or manage SSH keys. Session Manager also makes it easy to comply with corporate policies that require controlled access to instances, strict security practices, and fully auditable logs with instance access details, while still providing end users with simple one-click cross-platform access to your Amazon EC2 instances. You can read more of the [more of the benefits of using Session Manager in the documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-session-manager.html). + +To use the AWS CLI to run session commands, you must be using version 1.16.12 of the CLI, and you must have [installed the Session Manager plugin on your local machine](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html). + If you do need to connect directly to instances, it's best (and for instances in a private subnets, a requirement) to use a bastion host, otherwise known as a jump box. A bastion host is an EC2 instance that is publicly accessible, and also has access to private resources, allowing it to function as a secure go-between. You configure your EC2 instances to only accept ssh traffic from the bastion host, then you can ssh into the bastion host, and from there connect to your private resources. EC2 key pairs are required to ssh into any EC2 instance, including bastion hosts. If an attacker gains access to your key pair, they can use it to get into your bastion host, and thus your other resources. In order to prevent this kind of breach the bastion host template supports enabling [Multi-Factor Authentication (MFA)](https://en.wikipedia.org/wiki/Multi-factor_authentication), which is highly recommended diff --git a/cmd.sh b/cmd.sh new file mode 100755 index 00000000..97112ad6 --- /dev/null +++ b/cmd.sh @@ -0,0 +1 @@ +aws cloudformation create-stack --region=us-east-1 --stack-name startupkit-eb --template-body file://vpc-eb-rds.cfn.yml --capabilities CAPABILITY_IAM --parameters ParameterKey=DatabasePassword,ParameterValue=aquasush ParameterKey=TemplateBucket,ParameterValue=gjg-startupkit-templates ParameterKey=AppS3Bucket,ParameterValue=gjg-startupkit-testing ParameterKey=AppS3Key,ParameterValue=demoapp/1.zip ParameterKey=AvailabilityZone1,ParameterValue=us-east-1a ParameterKey=AvailabilityZone2,ParameterValue=us-east-1b ParameterKey=StackType,ParameterValue=rails \ No newline at end of file diff --git a/templates/bastion.cfn.yml b/templates/bastion.cfn.yml index 86d60807..88fdbe7b 100644 --- a/templates/bastion.cfn.yml +++ b/templates/bastion.cfn.yml @@ -19,7 +19,8 @@ Parameters: KeyName: Description: EC2 key pair name for bastion host SSH access - Type: AWS::EC2::KeyPair::KeyName + Type: String + Default: '' LogRetentionInDays: Description: Number of days you would like your CloudWatch Logs to be retained @@ -36,6 +37,9 @@ Parameters: - true - false +Conditions: + HasKeyName: !Not [ !Equals [ !Ref KeyName, '' ]] + Mappings: # Amazon Linux AMI - https://aws.amazon.com/amazon-linux-ami/ @@ -211,7 +215,7 @@ Resources: Properties: InstanceType: t2.micro - KeyName: !Ref KeyName + KeyName: !If [ HasKeyName, !Ref KeyName, !Ref "AWS::NoValue" ] NetworkInterfaces: - NetworkInterfaceId: !Ref BastionNetworkInterface DeviceIndex: 0 diff --git a/templates/elastic-beanstalk.cfn.yml b/templates/elastic-beanstalk.cfn.yml index 03fe3d66..4d8f7f64 100644 --- a/templates/elastic-beanstalk.cfn.yml +++ b/templates/elastic-beanstalk.cfn.yml @@ -43,6 +43,14 @@ Parameters: MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" + Bastion: + Description: Flag on whether to allow SSH access to instances via bastion instead of Session Manager + Type: String + Default: false + AllowedValues: + - true + - false + DatabaseStackName: Description: Name of an active CloudFormation stack of database resources Type: String @@ -80,7 +88,8 @@ Parameters: EC2KeyPairName: Description: EC2 key pair name for SSH access - Type: AWS::EC2::KeyPair::KeyName + Type: String + Default: '' DevInstanceType: Description: The instance type for the dev environment @@ -122,16 +131,19 @@ Parameters: Conditions: CreateProdEnv: !Equals [ !Ref EnvironmentName, prod ] + HasKeyName: !Not [ !Equals [ !Ref EC2KeyPairName, '' ]] TlsEnabled: !Not [ !Equals [ !Ref SSLCertificateArn, "" ] ] + CreateBastion: !Equals [ !Ref Bastion, true ] + Mappings: # Maps stack type parameter to solution stack name string StackMap: node: stackName: 64bit Amazon Linux 2018.03 v4.5.3 running Node.js rails: - stackName: 64bit Amazon Linux 2018.03 v2.8.3 running Ruby 2.4 (Puma) + stackName: 64bit Amazon Linux 2018.03 v2.8.7 running Ruby 2.4 (Puma) spring: stackName: 64bit Amazon Linux 2018.03 v3.0.3 running Tomcat 8 Java 8 python: @@ -213,18 +225,20 @@ Resources: Value: !Ref AutoScalingMaxInstanceCount - Namespace: aws:autoscaling:launchconfiguration - OptionName: SecurityGroups - Value: - Fn::ImportValue: !Sub "${NetworkStackName}-AppSecurityGroupID" + OptionName: SSHSourceRestriction + Value: !If + - CreateBastion + - "Fn::Join": + - ',' + - - 'tcp, 22, 22' + - !ImportValue + "Fn::Sub": "${NetworkStackName}-BastionGroupID" + - 'tcp, 22, 22, 127.0.0.1/32' - Namespace: aws:autoscaling:launchconfiguration - OptionName: SSHSourceRestriction + OptionName: SecurityGroups Value: - "Fn::Join": - - ',' - - - 'tcp, 22, 22' - - !ImportValue - "Fn::Sub": "${NetworkStackName}-BastionGroupID" + Fn::ImportValue: !Sub "${NetworkStackName}-AppSecurityGroupID" - Namespace: aws:autoscaling:launchconfiguration OptionName: InstanceType @@ -236,7 +250,7 @@ Resources: - Namespace: aws:autoscaling:launchconfiguration OptionName: EC2KeyName - Value: !Ref EC2KeyPairName + Value: !If [ HasKeyName, !Ref EC2KeyPairName, !Ref "AWS::NoValue" ] - Namespace: aws:autoscaling:updatepolicy:rollingupdate OptionName: RollingUpdateEnabled diff --git a/templates/vpc.cfn.yml b/templates/vpc.cfn.yml index 874ff4f8..28470f49 100644 --- a/templates/vpc.cfn.yml +++ b/templates/vpc.cfn.yml @@ -4,8 +4,8 @@ AWSTemplateFormatVersion: 2010-09-09 Description: SASKV5N VPC # This VPC stack should be created first before any other -# CloudFormation stacks, such as a bastion stack, database -# stack and application stack +# CloudFormation stacks, such as a database stack +# and application stack Parameters: AvailabilityZone1: @@ -18,6 +18,14 @@ Parameters: Type: AWS::EC2::AvailabilityZone::Name ConstraintDescription: Must be a valid availability zone + Bastion: + Description: Flag on whether to allow SSH access to instances via bastion instead of Session Manager + Type: String + Default: false + AllowedValues: + - true + - false + SSHFrom: Description: Limit SSH access to bastion hosts to a CIDR IP block Type: String @@ -76,6 +84,7 @@ Metadata: Conditions: CreateSingleNatGateway: !Equals [ !Ref SingleNatGateway, true ] CreateMultipleNatGateways: !Not [ Condition: CreateSingleNatGateway ] + CreateBastion: !Equals [ !Ref Bastion, true ] Mappings: @@ -230,10 +239,6 @@ Resources: IpProtocol: tcp ToPort: !Ref AppIngressPort FromPort: !Ref AppIngressPort - - SourceSecurityGroupId: !Ref BastionSecurityGroup - IpProtocol: tcp - ToPort: 22 - FromPort: 22 Tags: - Key: Name Value: !Sub "${AWS::StackName}-AppSecurityGroup" @@ -248,6 +253,7 @@ Resources: SourceSecurityGroupId: !Ref ELBSecurityGroup AppSecurityGroupFromBastionIngress: + Condition: CreateBastion Type: AWS::EC2::SecurityGroupIngress # prevent security group circular references Properties: GroupId: !Ref AppSecurityGroup @@ -257,6 +263,7 @@ Resources: SourceSecurityGroupId: !Ref BastionSecurityGroup BastionSecurityGroup: + Condition: CreateBastion Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable access to the bastion host @@ -284,6 +291,7 @@ Resources: Value: !Sub "${AWS::StackName}-BastionSecurityGroup" BastionSecurityGroupToAppEgress: + Condition: CreateBastion Type: AWS::EC2::SecurityGroupEgress # prevent security group circular references Properties: GroupId: !Ref BastionSecurityGroup @@ -293,6 +301,7 @@ Resources: DestinationSecurityGroupId: !Ref AppSecurityGroup BastionSecurityGroupToDbEgress: + Condition: CreateBastion Type: AWS::EC2::SecurityGroupEgress # prevent security group circular references Properties: GroupId: !Ref BastionSecurityGroup @@ -320,6 +329,7 @@ Resources: Value: !Sub "${AWS::StackName}-DbSecurityGroup" DbSecurityGroupFromBastionIngress: + Condition: CreateBastion Type: AWS::EC2::SecurityGroupIngress # prevent security group circular references Properties: GroupId: !Ref DbSecurityGroup @@ -482,6 +492,7 @@ Outputs: BastionSecurityGroup: Description: Security group ID for bastion host + Condition: CreateBastion Value: !GetAtt BastionSecurityGroup.GroupId Export: Name: !Sub "${AWS::StackName}-BastionGroupID" diff --git a/vpc-eb-rds.cfn.yml b/vpc-eb-rds.cfn.yml new file mode 100644 index 00000000..5f91d52d --- /dev/null +++ b/vpc-eb-rds.cfn.yml @@ -0,0 +1,563 @@ +--- +AWSTemplateFormatVersion: 2010-09-09 + +Description: SASKV5 VPC + Elastic Beanstalk + Database + +Parameters: + + TemplateBucket: + Type: String + Default: awslabs-startup-kit-templates-deploy-v5 + Description: The template bucket for the CloudFormation templates + + EnvironmentName: + Type: String + Description: Environment name - dev or prod + Default: dev + AllowedValues: + - dev + - prod + ConstraintDescription: Specify either dev or prod + + # vpc.cfn.yml parameters + AvailabilityZone1: + Description: The first availability zone in the region + Type: AWS::EC2::AvailabilityZone::Name + ConstraintDescription: Must be a valid availability zone + + AvailabilityZone2: + Description: The second availability zone in the region + Type: AWS::EC2::AvailabilityZone::Name + ConstraintDescription: Must be a valid availability zone + + ELBIngressPort: + Description: The ELB ingress port used by security groups + Type: Number + MinValue: 0 + MaxValue: 65535 + ConstraintDescription: TCP ports must be between 0 - 65535 + Default: 80 + + AppIngressPort: + Description: The application ingress port used by security groups + Type: Number + MinValue: 0 + MaxValue: 65535 + ConstraintDescription: TCP ports must be between 0 - 65535 + Default: 80 + + # bastion.cfn.yml parameters + Bastion: + Description: Flag on whether to allow SSH access to instances via bastion instead of Session Manager + Type: String + Default: false + AllowedValues: + - true + - false + + KeyName: + Description: EC2 key pair name for bastion host SSH access + Type: String + Default: '' + + LogRetentionInDays: + Description: Number of days you would like your CloudWatch Logs to be retained + Type: Number + Default: 90 + + # For more information on the google-authenticator PAM module, see: https://github.com/google/google-authenticator-libpam + MFA: + Description: Set to true to install MFA using the google-authenticator PAM module on your bastion host + Type: String + ConstraintDescription: Value must be true or false + Default: false + AllowedValues: + - true + - false + + # elastic-beanstalk.cfn.yml parameters + StackType: + Description: node, rails, python, python3 or spring. + Type: String + Default: python + AllowedValues: + - node + - rails + - spring + - python + - python3 + ConstraintDescription: Specify node, rails, python, python3 or spring. + + AppS3Bucket: + Description: S3 Bucket containing your application package + Type: String + MinLength: 1 + MaxLength: 255 + + AppS3Key: + Description: S3 Bucket key for your application package + Type: String + MinLength: 1 + MaxLength: 255 + + EbInstanceType: + Description: The instance type for Elastic Beanstalk + Type: String + Default: t2.small + ConstraintDescription: Instance type not supported + AllowedValues: + - t2.small + - t2.medium + - t2.large + - t2.xlarge + - t2.2xlarge + - m5.large + - m5.xlarge + - m5.2xlarge + - m5.4xlarge + - m5.12xlarge + - m5.24xlarge + - r4.large + - r4.xlarge + - r4.2xlarge + - r4.4xlarge + - r4.8xlarge + - r4.16xlarge + + SSLCertificateArn: + Description: The optional SSL/TLS certificate ARN + Type: String + MinLength: 0 + MaxLength: 2048 + Default: "" + + AutoScalingMinInstanceCount: + Description: Minimum number of EC2 instances for Auto Scaling + Type: Number + MinValue: 1 + MaxValue: 20 + Default: 2 + ConstraintDescription: Specify a number between 1 - 20 + + AutoScalingMaxInstanceCount: + Description: Maximum number of EC2 instances for Auto Scaling + Type: Number + MinValue: 1 + MaxValue: 20 + Default: 6 + ConstraintDescription: Specify a number between 1 - 20 + + # aurora.cfn.yml and/or db.cfn.yml parameters + DatabaseUser: + Default: startupadmin + Type: String + Description: Database admin account name + MinLength: 5 + MaxLength: 16 + AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription: Name must begin with a letter and contain only alphanumeric characters + + DatabasePassword: + NoEcho: true + Type: String + Description: Database admin account password + MinLength: 6 + MaxLength: 41 + AllowedPattern: "[a-zA-Z0-9]*" + ConstraintDescription: Password must contain only alphanumeric characters + + DatabaseName: + Default: StartupDB + Type: String + Description: Database name + MinLength: 1 + MaxLength: 30 + AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription: Name must begin with a letter and contain only alphanumeric characters + + DatabaseEngine: + Default: aurora + Type: String + Description: Database engines - Aurora MySQL, Aurora PostgreSQL, PostgreSQL, MariaDB and MySQL + ConstraintDescription: Choose an engine from the drop down + AllowedValues: + - aurora + - aurora-postgresql + - postgres + - mariadb + - mysql + + EncryptionAtRest: + Default: false + Type: String + Description: The optional flag for encryption at rest (db.t2.small and above) + ConstraintDescription: Only true or false are allowed + AllowedValues: + - true + - false + + DatabaseSize: + Default: 5 + Type: String + Description: Database storage size in gigabytes (GB) - Not applicable for Aurora + MinLength: 1 + AllowedPattern: "[5-9]|[1-9][0-9]+" + ConstraintDescription: Enter a size of at least 5 GB + + DatabaseInstanceClass: + Default: db.t2.small + Type: String + Description: "Database instance class, e.g. db.t2.micro (free tier) - Engine support: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html" + ConstraintDescription: DB instance class not supported + AllowedValues: + - db.t2.micro + - db.t2.small + - db.t2.medium + - db.t2.large + - db.t2.xlarge + - db.t2.2xlarge + - db.m4.large + - db.m4.xlarge + - db.m4.2xlarge + - db.m4.4xlarge + - db.m4.10xlarge + - db.m4.16xlarge + - db.r4.large + - db.r4.xlarge + - db.r4.2xlarge + - db.r4.4xlarge + - db.r4.8xlarge + - db.r4.16xlarge + + DatabaseEnableAlarms: + Default: false + Type: String + Description: Set to true to enable (additional charges - https://aws.amazon.com/cloudwatch/pricing/ - aurora, postgres, mariadb, mysql) + ConstraintDescription: Only true or false are allowed + AllowedValues: + - true + - false + + DatabaseEnhancedMonitoring: + Default: false + Type: String + Description: The optional flag for enhanced monitoring (additional charges apply - https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.htm - aurora, postgres, mariadb, mysql) + ConstraintDescription: Only true or false are allowed + AllowedValues: + - true + - false + + DatabaseAlarmMaxCpuPercent: + Description: Database CPU % max for alarm (aurora, postgres, mariadb, mysql) + Type: Number + Default: 80 + MinValue: 1 + MaxValue: 99 + ConstraintDescription: Must be a percentage between 1-99% + + DatabaseAlarmReadLatencyMaxSeconds: + Description: Read latency max in seconds for alarm (aurora, postgres, mariadb, mysql) + Type: Number + Default: 1 + MinValue: 1 + + DatabaseAlarmWriteLatencyMaxSeconds: + Description: Write latency max in seconds for alarm (aurora, postgres, mariadb, mysql) + Type: Number + Default: 1 + MinValue: 1 + + DatabaseAlarmEvaluationPeriods: + Description: The number of periods over which data is compared to the specified threshold (aurora, postgres, mariadb, mysql) + Type: Number + Default: 2 + MinValue: 2 + ConstraintDescription: Must be at least one + + DatabaseAlarmEvaluationPeriodSeconds: + Description: The time over which the specified statistic is applied. Specify time in seconds, in multiples of 60. Enhanced monitoring must be enabled if less than 500 second (aurora, postgres, mariadb, mysql) + Type: Number + Default: 300 + MinValue: 60 + ConstraintDescription: Must be at least 60 seconds + + # Default is 500 MB + DatabaseAlarmMinFreeSpaceInBytes: + Default: 524288000 + Type: Number + Description: Number of min free space bytes for alarm (postgres, mariadb, mysql) + MinValue: 1 + ConstraintDescription: A value of one byte or more + + # Default is 200 MB + DatabaseAlarmSwapUsageInBytes: + Default: 209715200 + Type: Number + Description: Number of swap usage bytes for alarm (postgres, mariadb, mysql) + MinValue: 1 + ConstraintDescription: A value of one byte or more + +Metadata: + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: Environment + Parameters: + - EnvironmentName + - Label: + default: Region Availability Zones + Parameters: + - AvailabilityZone1 + - AvailabilityZone2 + - Label: + default: Bastion + Parameters: + - KeyName + - LogRetentionInDays + - MFA + - SSHFrom + - Label: + default: Database + Parameters: + - DatabaseEngine + - DatabaseInstanceClass + - DatabaseUser + - DatabasePassword + - DatabaseName + - DatabaseSize + - EncryptionAtRest + - DatabaseEnableAlarms + - DatabaseEnhancedMonitoring + - DatabaseAlarmMaxCpuPercent + - DatabaseAlarmReadLatencyMaxSeconds + - DatabaseAlarmWriteLatencyMaxSeconds + - DatabaseAlarmEvaluationPeriods + - DatabaseAlarmEvaluationPeriodSeconds + - DatabaseAlarmMinFreeSpaceInBytes + - DatabaseAlarmSwapUsageInBytes + - Label: + default: Application Global + Parameters: + - AppIngressPort + - AppProtocol + - Label: + default: Elastic Beanstalk + Parameters: + - StackType + - EbInstanceType + - AppS3Bucket + - AppS3Key + - EC2KeyPairName + - AutoScalingMinInstanceCount + - AutoScalingMaxInstanceCount + - Label: + default: Load Balancer + Parameters: + - ELBIngressPort + - SSLCertificateArn + ParameterLabels: + AvailabilityZone1: + default: Availability Zone 1 + AvailabilityZone2: + default: Availability Zone 2 + ELBIngressPort: + default: Port + AppIngressPort: + default: Port + AppProtocol: + default: Protocol + KeyName: + default: EC2 Key Pair + LogRetentionInDays: + default: Log Retention + MFA: + default: Multi-Factor + TemplateBucket: + default: CloudFormation Bucket + EnvironmentName: + default: Environment + SSLCertificateArn: + default: SSL Certificate + DatabaseUser: + default: User + DatabasePassword: + default: Password + DatabaseName: + default: Name + DatabaseSize: + default: Size + DatabaseEngine: + default: Engine + EncryptionAtRest: + default: Encryption at Rest + DatabaseInstanceClass: + default: Instance Type + StackType: + default: Stack Type + EbInstanceType: + default: Instance Type + AppS3Bucket: + default: App S3 Bucket + AppS3Key: + default: App S3 Key + AutoScalingMinInstanceCount: + default: Min Instances + AutoScalingMaxInstanceCount: + default: Max Instances + DatabaseAlarmMaxCpuPercent: + default: Alarm Max CPU% + DatabaseAlarmReadLatencyMaxSeconds: + default: Alarm Max Read Latency + DatabaseAlarmWriteLatencyMaxSeconds: + default: Alarm Max Write Latency + DatabaseAlarmEvaluationPeriods: + default: Alarm Period(s) + DatabaseAlarmEvaluationPeriodSeconds: + default: Alarm Period Seconds + DatabaseEnhancedMonitoring: + default: Enhanced Monitoring + DatabaseAlarmMinFreeSpaceInBytes: + default: Min Free Space + DatabaseAlarmSwapUsageInBytes: + default: Max Swap Use + DatabaseEnableAlarms: + default: Enable Alarms + +Conditions: + + IsProd: !Equals [ !Ref EnvironmentName, prod ] + + IsAurora: !Or [ !Equals [ !Ref DatabaseEngine, aurora ], !Equals [ !Ref DatabaseEngine, aurora-postgresql ] ] + + IsNotAurora: !Not [ Condition: IsAurora ] + + CreateBastion: !And [ !Equals [ !Ref Bastion, true ], !Not [ !Equals [ !Ref KeyName, '' ] ] ] + +Resources: + + VpcStack: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: !Sub https://s3.amazonaws.com/${TemplateBucket}/templates/vpc.cfn.yml + Parameters: + AvailabilityZone1: !Ref AvailabilityZone1 + AvailabilityZone2: !Ref AvailabilityZone2 + ELBIngressPort: !Ref ELBIngressPort + AppIngressPort: !Ref AppIngressPort + SingleNatGateway: !If [ IsProd, false, true ] + Bastion: !Ref Bastion + + BastionStack: + Type: AWS::CloudFormation::Stack + Condition: CreateBastion + Properties: + TemplateURL: !Sub https://s3.amazonaws.com/${TemplateBucket}/templates/bastion.cfn.yml + Parameters: + NetworkStackName: !GetAtt VpcStack.Outputs.Name + KeyName: !If [ CreateBastion, !Ref KeyName, !Ref "AWS::NoValue" ] + LogRetentionInDays: !Ref LogRetentionInDays + MFA: !Ref MFA + DependsOn: VpcStack + + AuroraStack: + Type: AWS::CloudFormation::Stack + Condition: IsAurora + Properties: + TemplateURL: !Sub https://s3.amazonaws.com/${TemplateBucket}/templates/aurora.cfn.yml + Parameters: + NetworkStackName: !GetAtt VpcStack.Outputs.Name + EnvironmentName: !Ref EnvironmentName + DatabaseEngine: !Ref DatabaseEngine + DatabaseInstanceClass: !Ref DatabaseInstanceClass + DatabaseUser: !Ref DatabaseUser + DatabasePassword: !Ref DatabasePassword + DatabaseName: !Ref DatabaseName + EncryptionAtRest: !Ref EncryptionAtRest + EnableAlarms: !Ref DatabaseEnableAlarms + EnhancedMonitoring: !Ref DatabaseEnhancedMonitoring + DatabaseAlarmMaxCpuPercent: !Ref DatabaseAlarmMaxCpuPercent + DatabaseAlarmReadLatencyMaxSeconds: !Ref DatabaseAlarmReadLatencyMaxSeconds + DatabaseAlarmWriteLatencyMaxSeconds: !Ref DatabaseAlarmWriteLatencyMaxSeconds + DatabaseAlarmEvaluationPeriods: !Ref DatabaseAlarmEvaluationPeriods + DatabaseAlarmEvaluationPeriodSeconds: !Ref DatabaseAlarmEvaluationPeriodSeconds + DependsOn: VpcStack + + RdsStack: + Type: AWS::CloudFormation::Stack + Condition: IsNotAurora + Properties: + TemplateURL: !Sub https://s3.amazonaws.com/${TemplateBucket}/templates/db.cfn.yml + Parameters: + NetworkStackName: !GetAtt VpcStack.Outputs.Name + EnvironmentName: !Ref EnvironmentName + DatabaseEngine: !Ref DatabaseEngine + DatabaseInstanceClass: !Ref DatabaseInstanceClass + DatabaseUser: !Ref DatabaseUser + DatabasePassword: !Ref DatabasePassword + DatabaseName: !Ref DatabaseName + EncryptionAtRest: !Ref EncryptionAtRest + DatabaseSize: !Ref DatabaseSize + EnableAlarms: !Ref DatabaseEnableAlarms + EnhancedMonitoring: !Ref DatabaseEnhancedMonitoring + DatabaseAlarmMaxCpuPercent: !Ref DatabaseAlarmMaxCpuPercent + DatabaseAlarmReadLatencyMaxSeconds: !Ref DatabaseAlarmReadLatencyMaxSeconds + DatabaseAlarmWriteLatencyMaxSeconds: !Ref DatabaseAlarmWriteLatencyMaxSeconds + DatabaseAlarmEvaluationPeriods: !Ref DatabaseAlarmEvaluationPeriods + DatabaseAlarmEvaluationPeriodSeconds: !Ref DatabaseAlarmEvaluationPeriodSeconds + DatabaseAlarmMinFreeSpaceInBytes: !Ref DatabaseAlarmMinFreeSpaceInBytes + DatabaseAlarmSwapUsageInBytes: !Ref DatabaseAlarmSwapUsageInBytes + DependsOn: VpcStack + + ElasticBeanstalkStack: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: !Sub https://s3.amazonaws.com/${TemplateBucket}/templates/elastic-beanstalk.cfn.yml + Parameters: + ApplicationName: !Ref AWS::StackName + StackType: !Ref StackType + EnvironmentName: !Ref EnvironmentName + NetworkStackName: !GetAtt VpcStack.Outputs.Name + Bastion: !Ref Bastion + DatabaseStackName: !If [ IsAurora, !GetAtt AuroraStack.Outputs.Name, !GetAtt RdsStack.Outputs.Name ] + DatabaseName: !Ref DatabaseName + DatabasePassword: !Ref DatabasePassword + AppS3Bucket: !Ref AppS3Bucket + AppS3Key: !Ref AppS3Key + EC2KeyPairName: !If [ CreateBastion, !Ref KeyName, !Ref "AWS::NoValue" ] + DevInstanceType: !Ref EbInstanceType + ProdInstanceType: !Ref EbInstanceType + SSLCertificateArn: !Ref SSLCertificateArn + AutoScalingMinInstanceCount: !Ref AutoScalingMinInstanceCount + AutoScalingMaxInstanceCount: !Ref AutoScalingMaxInstanceCount + + +Outputs: + + Name: + Description: Aurora Stack Name + Value: !Ref AWS::StackName + Export: + Name: !Sub ${AWS::StackName}-Name + + VpcStackName: + Value: !GetAtt VpcStack.Outputs.Name + Export: + Name: !Sub ${AWS::StackName}-VpcStackName + + ElasticBeanstalkStackName: + Value: !GetAtt ElasticBeanstalkStack.Outputs.Name + Export: + Name: !Sub ${AWS::StackName}-ElasticBeanstalkStack + + AuroraStackName: + Value: !GetAtt AuroraStack.Outputs.Name + Condition: IsAurora + Export: + Name: !Sub ${AWS::StackName}-DatabaseStackName + + RdsStackName: + Value: !GetAtt RdsStack.Outputs.Name + Condition: IsNotAurora + Export: + Name: !Sub ${AWS::StackName}-DatabaseStackName +