--- AWSTemplateFormatVersion: '2010-09-09' Description: Elastic Beanstalk # App stack creation prerequisites: first create a VPC stack, then a DB stack. Parameters: ApplicationName: Description: Name of your application Type: String MinLength: 1 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" StackType: Description: node, rails, python, python3 or spring Type: String MinLength: 1 MaxLength: 255 AllowedValues: - node - rails - spring - python - python3 ConstraintDescription: Specify node, rails, python, python3 or spring EnvironmentName: Description: Environment name, either dev or prod. Type: String MinLength: 1 MaxLength: 255 AllowedValues: - dev - prod ConstraintDescription: Specify either dev or prod NetworkStackName: Description: Name of an active CloudFormation stack of networking resources Type: String MinLength: 1 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" DatabaseStackName: Description: Name of an active CloudFormation stack of database resources Type: String MinLength: 1 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" DatabaseName: Description: Database name (schema). Type: String MinLength: 1 MaxLength: 255 AllowedPattern: "^[a-zA-Z][-a-zA-Z0-9]*$" 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 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 EC2KeyPairName: Description: EC2 key pair name for SSH access Type: AWS::EC2::KeyPair::KeyName DevInstanceType: Description: The instance type for the dev environment Type: String MinLength: 1 MaxLength: 255 Default: t2.micro ProdInstanceType: Description: The instance type for the prod environment Type: String MinLength: 1 MaxLength: 255 Default: t2.large SSLCertificateArn: Description: The 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 Conditions: CreateProdEnv: !Equals [ !Ref EnvironmentName, prod ] TlsEnabled: !Not [ !Equals [ !Ref SSLCertificateArn, "" ] ] 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) spring: stackName: 64bit Amazon Linux 2018.03 v3.0.3 running Tomcat 8 Java 8 python: stackName: 64bit Amazon Linux 2018.03 v2.7.3 running Python 2.7 python3: stackName: 64bit Amazon Linux 2018.03 v2.7.3 running Python 3.6 Resources: ElasticBeanstalkServiceRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: | { "Statement": [{ "Effect": "Allow", "Principal": { "Service": [ "elasticbeanstalk.amazonaws.com" ]}, "Action": [ "sts:AssumeRole" ] }] } ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkEnhancedHealth - arn:aws:iam::aws:policy/service-role/AWSElasticBeanstalkService Application: Type: AWS::ElasticBeanstalk::Application Properties: ApplicationName: !Ref ApplicationName ApplicationVersion: Type: AWS::ElasticBeanstalk::ApplicationVersion Properties: ApplicationName: !Ref Application SourceBundle: S3Bucket: !Ref AppS3Bucket S3Key: !Ref AppS3Key Environment: Type: AWS::ElasticBeanstalk::Environment Properties: EnvironmentName: !Sub "${ApplicationName}-${EnvironmentName}" ApplicationName: !Ref Application TemplateName: !Ref ConfigurationTemplate VersionLabel: !Ref ApplicationVersion DependsOn: - ConfigurationTemplate - ApplicationVersion # The configuration template contains environment parameters such as those # that relate to the autoscaling group (e.g. size, triggers), placement of # resources in the VPC, load balancer setup, and environment variables ConfigurationTemplate: Type: AWS::ElasticBeanstalk::ConfigurationTemplate Properties: ApplicationName: !Ref Application SolutionStackName: !FindInMap [ StackMap, !Ref StackType, stackName ] OptionSettings: - Namespace: aws:elasticbeanstalk:environment OptionName: EnvironmentType Value: LoadBalanced - Namespace: aws:elasticbeanstalk:environment OptionName: LoadBalancerType Value: application - Namespace: aws:elasticbeanstalk:environment OptionName: ServiceRole Value: !Ref ElasticBeanstalkServiceRole # AUTOSCALING OPTIONS - Namespace: aws:autoscaling:asg OptionName: MinSize Value: !Ref AutoScalingMinInstanceCount - Namespace: aws:autoscaling:asg OptionName: MaxSize Value: !Ref AutoScalingMaxInstanceCount - Namespace: aws:autoscaling:launchconfiguration OptionName: SecurityGroups Value: Fn::ImportValue: !Sub "${NetworkStackName}-AppSecurityGroupID" - Namespace: aws:autoscaling:launchconfiguration OptionName: SSHSourceRestriction Value: "Fn::Join": - ',' - - 'tcp, 22, 22' - !ImportValue "Fn::Sub": "${NetworkStackName}-BastionGroupID" - Namespace: aws:autoscaling:launchconfiguration OptionName: InstanceType Value: !If [ CreateProdEnv, !Ref ProdInstanceType, !Ref DevInstanceType ] - Namespace: aws:autoscaling:launchconfiguration OptionName: IamInstanceProfile Value: !Ref AppInstanceProfile - Namespace: aws:autoscaling:launchconfiguration OptionName: EC2KeyName Value: !Ref EC2KeyPairName - Namespace: aws:autoscaling:updatepolicy:rollingupdate OptionName: RollingUpdateEnabled Value: true - Namespace: aws:autoscaling:updatepolicy:rollingupdate OptionName: RollingUpdateType Value: Health - Namespace: aws:autoscaling:trigger OptionName: MeasureName Value: CPUUtilization - Namespace: aws:autoscaling:trigger OptionName: Unit Value: Percent - Namespace: aws:autoscaling:trigger OptionName: UpperThreshold Value: 80 - Namespace: aws:autoscaling:trigger OptionName: LowerThreshold Value: 40 # VPC OPTIONS (PLACEMENT OF RESOURCES IN SUBNETS) - Namespace: aws:ec2:vpc OptionName: VPCId Value: Fn::ImportValue: !Sub "${NetworkStackName}-VpcID" - Namespace: aws:ec2:vpc OptionName: Subnets Value: "Fn::Join": - ',' - - !ImportValue "Fn::Sub": "${NetworkStackName}-PrivateSubnet1ID" - !ImportValue "Fn::Sub": "${NetworkStackName}-PrivateSubnet2ID" - Namespace: aws:ec2:vpc OptionName: ELBSubnets Value: "Fn::Join": - ',' - - !ImportValue "Fn::Sub": "${NetworkStackName}-PublicSubnet1ID" - !ImportValue "Fn::Sub": "${NetworkStackName}-PublicSubnet2ID" - Namespace: aws:elbv2:listener:default OptionName: ListenerEnabled Value: !If [ TlsEnabled, false, true ] - Namespace: aws:elbv2:loadbalancer OptionName: SecurityGroups Value: Fn::ImportValue: !Sub "${NetworkStackName}-ELBSecurityGroupID" - Namespace: aws:elbv2:loadbalancer OptionName: ManagedSecurityGroup Value: Fn::ImportValue: !Sub "${NetworkStackName}-ELBSecurityGroupID" - Namespace: aws:elbv2:listenerrule:default OptionName: PathPatterns Value: "/*" - Namespace: !Sub - "aws:elbv2:listener:${ListenPort}" - ListenPort: "Fn::ImportValue": !Sub "${NetworkStackName}-ELBIngressPort" OptionName: Protocol Value: !If [ TlsEnabled, HTTPS, HTTP ] - Namespace: !Sub - "aws:elbv2:listener:${ListenPort}" - ListenPort: "Fn::ImportValue": !Sub "${NetworkStackName}-ELBIngressPort" OptionName: Rules Value: default - Namespace: !Sub - "aws:elbv2:listener:${ListenPort}" - ListenPort: "Fn::ImportValue": !Sub "${NetworkStackName}-ELBIngressPort" OptionName: SSLCertificateArns Value: !Ref SSLCertificateArn # CLOUDWATCH LOGS - Namespace: aws:elasticbeanstalk:cloudwatch:logs OptionName: StreamLogs Value: true - Namespace: aws:elasticbeanstalk:cloudwatch:logs OptionName: DeleteOnTerminate Value: true # ENVIRONMENT VARIABLES - COMMON TO ALL STACKS - Namespace: aws:elasticbeanstalk:application:environment OptionName: AWS_REGION Value: !Ref AWS::Region # ENVIRONMENT VARIABLES - NODE, RAILS - Move to parameter store - Namespace: aws:elasticbeanstalk:application:environment OptionName: DB_PASSWORD Value: !Ref DatabasePassword - Namespace: aws:elasticbeanstalk:application:environment OptionName: DB_USER Value: Fn::ImportValue: !Sub ${DatabaseStackName}-DatabaseUser - Namespace: aws:elasticbeanstalk:application:environment OptionName: DB_NAME Value: !Ref DatabaseName - Namespace: aws:elasticbeanstalk:application:environment OptionName: DB_HOST Value: Fn::ImportValue: !Sub "${DatabaseStackName}-DatabaseURL" # ENVIRONMENT VARIABLES - SPRING - Namespace: aws:elasticbeanstalk:application:environment OptionName: spring.datasource.password Value: !Ref DatabasePassword - Namespace: aws:elasticbeanstalk:application:environment OptionName: spring.datasource.username Value: Fn::ImportValue: !Sub "${DatabaseStackName}-DatabaseUser" - Namespace: aws:elasticbeanstalk:application:environment OptionName: spring.datasource.url Value: "Fn::Join": - '' - - 'jdbc:mysql://' - !ImportValue "Fn::Sub": "${DatabaseStackName}-DatabaseURL" - ':3306/' - Ref: DatabaseName # IAM resources AppRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole AppPolicies: Type: AWS::IAM::Policy Properties: PolicyName: App Roles: - !Ref AppRole PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: "*" Resource: "*" AppInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - !Ref AppRole Outputs: Name: Description: Elastic Beanstalk Stack Name Value: !Ref AWS::StackName Export: Name: !Sub ${AWS::StackName}-Name EnvironmentURL: Description: Environment URL Value: !GetAtt Environment.EndpointURL Export: Name: !Sub "${AWS::StackName}-EnvironmentURL" EnvironmentName: Description: Environment Name Value: !Sub "${ApplicationName}-${EnvironmentName}" Export: Name: !Sub "${AWS::StackName}-EnvironmentName" TypeOfStack: Description: Stack type Value: !Ref StackType Export: Name: !Sub "${AWS::StackName}-TypeOfStack"