def add_resources(self): """Add resources to template.""" template = self.template variables = self.get_variables() targetgroup = template.add_resource( elasticloadbalancingv2.TargetGroup( 'TargetGroup', HealthCheckIntervalSeconds=variables[ 'HealthCheckIntervalSeconds'].ref, HealthCheckPath=variables['HealthCheckPath'].ref, HealthCheckPort=variables['HealthCheckPort'].ref, HealthCheckProtocol=variables['HealthCheckProtocol'].ref, HealthCheckTimeoutSeconds=variables[ 'HealthCheckTimeoutSeconds'].ref, HealthyThresholdCount=variables['HealthyThresholdCount'].ref, UnhealthyThresholdCount=variables['UnhealthyThresholdCount']. ref, Matcher=elasticloadbalancingv2.Matcher( HttpCode=variables['HealthCheckSuccessCodes'].ref), Name=variables['TargetGroupName'].ref, Port=variables['AppPort'].ref, Protocol=variables['AppProtocol'].ref, Tags=Tags(Application=variables['ApplicationName'].ref, Environment=variables['EnvironmentName'].ref), TargetType=variables['TargetType'].ref, VpcId=variables['VpcId'].ref)) template.add_output( Output("{}Arn".format(targetgroup.title), Description="ARN of the Target Group", Value=Ref(targetgroup), Export=Export( Sub('${AWS::StackName}-%sArn' % targetgroup.title))))
def create_target_group(stack, name, port, protocol='HTTPS', targets=[], http_codes='200', health_check_path='/', target_type='instance', attributes=False): """Add Target Group Resource.""" target_objects = [] for target in targets: target_objects.append(alb.TargetDescription(Id=target)) tg_atts = [] if not attributes: tg_atts.append( alb.TargetGroupAttribute( Key='deregistration_delay.timeout_seconds', Value='300')) else: for att, value in attributes.items(): tg_atts.append(alb.TargetGroupAttribute(Key=att, Value=value)) if http_codes is not None: return stack.stack.add_resource( alb.TargetGroup('{0}TargetGroup'.format(name), HealthCheckIntervalSeconds='30', HealthCheckProtocol=protocol, HealthCheckTimeoutSeconds='10', HealthyThresholdCount='4', HealthCheckPath=health_check_path, Matcher=alb.Matcher(HttpCode=http_codes), Name='{0}Target'.format(name), Port=port, Protocol=protocol, Targets=target_objects, TargetType=target_type, UnhealthyThresholdCount='3', TargetGroupAttributes=tg_atts, VpcId=Ref(stack.vpc))) return stack.stack.add_resource( alb.TargetGroup('{0}TargetGroup'.format(name), HealthCheckIntervalSeconds='30', HealthCheckProtocol=protocol, HealthCheckTimeoutSeconds='10', HealthyThresholdCount='3', Name='{0}Target'.format(name), Port=port, Protocol=protocol, Targets=targets, UnhealthyThresholdCount='3', TargetType=target_type, TargetGroupAttributes=tg_atts, VpcId=Ref(stack.vpc)))
def handle(self, chain_context): chain_context.metadata[META_TARGET_GROUP_NAME] = self.name template = chain_context.template template.add_resource( alb.TargetGroup(self.name, HealthCheckPath="/", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=alb.Matcher(HttpCode="200"), Port=self.port, Protocol="HTTP", UnhealthyThresholdCount="3", VpcId=self.vpc_id))
def create_target_group(self): t = self.template required_attributes = dict( Port=self.vars['ContainerPort'], Protocol=self.vars['TargetGroupProtocol'], TargetType='ip', VpcId=self.vars['VpcId'], ) if self.vars['HealthCheckAttributes']: if 'Matcher' in self.vars['HealthCheckAttributes']: self.vars['HealthCheckAttributes']['Matcher'] = elb.Matcher( **self.vars['HealthCheckAttributes']['Matcher']) tg_attributes = self.vars['HealthCheckAttributes'].copy() else: tg_attributes = dict() tg_attributes.update(required_attributes) return t.add_resource(elb.TargetGroup("TargetGroup", **tg_attributes))
def handle(self, chain_context): # todo: why is this not allowing a reference? name = '%sTargetGroup' % chain_context.instance_name chain_context.metadata[META_TARGET_GROUP_NAME] = name template = chain_context.template template.add_resource(alb.TargetGroup( name, HealthCheckPath="/", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=alb.Matcher(HttpCode="200"), Port=self.port, Protocol="HTTP", UnhealthyThresholdCount="3", VpcId=self.vpc_id ))
Join("-", [ Select(0, Split("-", Ref("AWS::StackName"))), "cluster-public-subnets" ]))), SecurityGroups=[Ref("LoadBalancerSecurityGroup")], )) t.add_resource( elb.TargetGroup( "TargetGroup", DependsOn='LoadBalancer', HealthCheckIntervalSeconds="20", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="15", HealthyThresholdCount="5", Matcher=elb.Matcher(HttpCode="200"), Port=3000, Protocol="HTTP", UnhealthyThresholdCount="3", VpcId=ImportValue( Join("-", [ Select(0, Split("-", Ref("AWS::StackName"))), "cluster-vpc-id" ])), )) t.add_resource( elb.Listener("Listener", Port="3000", Protocol="HTTP", LoadBalancerArn=Ref("LoadBalancer"), DefaultActions=[
def main(): t = Template("A template to create a load balanced autoscaled Web flask deployment using ansible.") addMapping(t) ### VPC CONFIGURATION ### vpc = ec2.VPC( "MainVPC", CidrBlock="10.1.0.0/16" ) t.add_resource(vpc) vpc_id = Ref(vpc) subnet_1 = ec2.Subnet( "WebAppSubnet1", t, AvailabilityZone="us-east-1a", CidrBlock="10.1.0.0/24", MapPublicIpOnLaunch=True, VpcId=vpc_id, ) subnet_1_id = Ref(subnet_1) subnet_2 = ec2.Subnet( "WebAppSubnet2", t, AvailabilityZone="us-east-1b", CidrBlock="10.1.1.0/24", MapPublicIpOnLaunch=True, VpcId=vpc_id, ) subnet_2_id = Ref(subnet_2) ### NETWORKING ### igw = ec2.InternetGateway("internetGateway", t) gateway_to_internet = ec2.VPCGatewayAttachment( "GatewayToInternet", t, VpcId=vpc_id, InternetGatewayId=Ref(igw) ) route_table = ec2.RouteTable( "subnetRouteTable", t, VpcId=vpc_id ) route_table_id = Ref(route_table) internet_route = ec2.Route( "routeToInternet", t, DependsOn=gateway_to_internet, DestinationCidrBlock="0.0.0.0/0", GatewayId=Ref(igw), RouteTableId=route_table_id ) subnet_1_route_assoc = ec2.SubnetRouteTableAssociation( "Subnet1RouteAssociation", t, RouteTableId=route_table_id, SubnetId=Ref(subnet_1) ) subnet_2_route_assoc = ec2.SubnetRouteTableAssociation( "Subnet2RouteAssociation", t, RouteTableId=route_table_id, SubnetId=Ref(subnet_2) ) http_ingress = { "CidrIp": "0.0.0.0/0", "Description": "Allow HTTP traffic in from internet.", "IpProtocol": "tcp", "FromPort": 80, "ToPort": 80, } ssh_ingress = { "CidrIp": "0.0.0.0/0", "Description": "Allow SSH traffic in from internet.", "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, } elb_sg = ec2.SecurityGroup( "elbSecurityGroup", t, GroupName="WebGroup", GroupDescription="Allow web traffic in from internet to ELB", VpcId=vpc_id, SecurityGroupIngress=[ http_ingress ]) ssh_sg = ec2.SecurityGroup( "sshSecurityGroup", t, GroupName="SSHGroup", GroupDescription="Allow SSH traffic in from internet", VpcId=vpc_id, SecurityGroupIngress=[ ssh_ingress ] ) elb_sg_id = Ref(elb_sg) ssh_sg_id = Ref(ssh_sg) autoscale_ingress = { "SourceSecurityGroupId": elb_sg_id, "Description": "Allow web traffic in from ELB", "IpProtocol": "tcp", "FromPort": 80, "ToPort": 80 } autoscale_sg = ec2.SecurityGroup( "WebAutoscaleSG", t, GroupName="AutoscaleGroup", GroupDescription="Allow web traffic in from elb on port 80", VpcId=vpc_id, SecurityGroupIngress=[ autoscale_ingress ] ) autoscale_sg_id = Ref(autoscale_sg) # BUCKETS app_bucket = s3.Bucket( "CodeDeployApplicationBucket", t, ) ### LOAD BALANCING ### Web_elb = elb.LoadBalancer( "WebElb", t, Name="WebElb", # TODO: Fix for name conflict Subnets=[subnet_1_id, subnet_2_id], SecurityGroups=[elb_sg_id] ) Web_target_group = elb.TargetGroup( "WebTargetGroup", t, DependsOn=Web_elb, HealthCheckPath="/health", HealthCheckPort=80, HealthCheckProtocol="HTTP", Matcher=elb.Matcher(HttpCode="200"), Name="NginxTargetGroup", Port=80, Protocol="HTTP", VpcId=vpc_id ) Web_listener = elb.Listener( "WebListener", t, LoadBalancerArn=Ref(Web_elb), DefaultActions=[ elb.Action("forwardAction", TargetGroupArn=Ref(Web_target_group), Type="forward" ) ], Port=80, Protocol="HTTP" ) ### AUTOSCALING ### # Everything after sudo -u ubuntu is one command # The sudo command is required to properly set file permissions when # running the ansible script as it assumes running from non root user lc_user_data = Base64(Join("\n", [ "#!/bin/bash", "apt-add-repository -y ppa:ansible/ansible", "apt-get update && sudo apt-get -y upgrade", "apt-get -y install git", "apt-get -y install ansible", "cd /home/ubuntu/", "sudo -H -u ubuntu bash -c '" "export LC_ALL=C.UTF-8 && " "export LANG=C.UTF-8 && " "ansible-pull -U https://github.com/DameonSmith/aws-meetup-ansible.git --extra-vars \"user=ubuntu\"'" ])) web_instance_role = iam.Role( "webInstanceCodeDeployRole", t, AssumeRolePolicyDocument={ 'Statement': [{ 'Effect': 'Allow', 'Principal': { 'Service': 'ec2.amazonaws.com' }, 'Action': 'sts:AssumeRole' }] }, Policies=[ iam.Policy( PolicyName="CodeDeployS3Policy", PolicyDocument=aws.Policy( Version='2012-10-17', Statement=[ aws.Statement( Sid='CodeDeployS3', Effect=aws.Allow, Action=[ aws_s3.PutObject, aws_s3.GetObject, aws_s3.GetObjectVersion, aws_s3.DeleteObject, aws_s3.ListObjects, aws_s3.ListBucket, aws_s3.ListBucketVersions, aws_s3.ListAllMyBuckets, aws_s3.ListMultipartUploadParts, aws_s3.ListBucketMultipartUploads, aws_s3.ListBucketByTags, ], Resource=[ GetAtt(app_bucket, 'Arn'), Join('', [ GetAtt(app_bucket, 'Arn'), '/*', ]), "arn:aws:s3:::aws-codedeploy-us-east-2/*", "arn:aws:s3:::aws-codedeploy-us-east-1/*", "arn:aws:s3:::aws-codedeploy-us-west-1/*", "arn:aws:s3:::aws-codedeploy-us-west-2/*", "arn:aws:s3:::aws-codedeploy-ca-central-1/*", "arn:aws:s3:::aws-codedeploy-eu-west-1/*", "arn:aws:s3:::aws-codedeploy-eu-west-2/*", "arn:aws:s3:::aws-codedeploy-eu-west-3/*", "arn:aws:s3:::aws-codedeploy-eu-central-1/*", "arn:aws:s3:::aws-codedeploy-ap-northeast-1/*", "arn:aws:s3:::aws-codedeploy-ap-northeast-2/*", "arn:aws:s3:::aws-codedeploy-ap-southeast-1/*", "arn:aws:s3:::aws-codedeploy-ap-southeast-2/*", "arn:aws:s3:::aws-codedeploy-ap-south-1/*", "arn:aws:s3:::aws-codedeploy-sa-east-1/*", ] ) ] ) ) ] ) web_instance_profile = iam.InstanceProfile( "webInstanceProfile", t, Path='/', Roles=[Ref(web_instance_role)], ) Web_launch_config = autoscaling.LaunchConfiguration( "webLaunchConfig", t, ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), # TODO: Remove magic string SecurityGroups=[ssh_sg_id, autoscale_sg_id], IamInstanceProfile=Ref(web_instance_profile), InstanceType="t2.micro", BlockDeviceMappings= [{ "DeviceName": "/dev/sdk", "Ebs": {"VolumeSize": "10"} }], UserData= lc_user_data, KeyName="advanced-cfn", ) Web_autoscaler = autoscaling.AutoScalingGroup( "WebAutoScaler", t, LaunchConfigurationName=Ref(Web_launch_config), MinSize="2", # TODO: Change to parameter MaxSize="2", VPCZoneIdentifier=[subnet_2_id, subnet_1_id], TargetGroupARNs= [Ref(Web_target_group)] ) t.add_output([ Output( "ALBDNS", Description="The DNS name for the application load balancer.", Value=GetAtt(Web_elb, "DNSName") ) ]) # DEVTOOLS CONFIG codebuild_service_role = iam.Role( "CMSCodeBuildServiceRole", t, AssumeRolePolicyDocument={ 'Statement': [{ 'Effect': 'Allow', 'Principal': { 'Service': ['codebuild.amazonaws.com'] }, 'Action': ['sts:AssumeRole'] }] }, Policies=[ iam.Policy( PolicyName="CloudWatchLogsPolicy", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Sid='logs', Effect=aws.Allow, Action=[ aws_logs.CreateLogGroup, aws_logs.CreateLogStream, aws_logs.PutLogEvents ], Resource=['*'] ) ] ) ), iam.Policy( PolicyName="s3AccessPolicy", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Sid='codebuilder', Effect=aws.Allow, Action=[ aws_s3.PutObject, aws_s3.GetObject, aws_s3.GetObjectVersion, aws_s3.DeleteObject ], Resource=[ GetAtt(app_bucket, 'Arn'), Join('', [ GetAtt(app_bucket, 'Arn'), '/*', ]) ] ) ] ) ) ] ) github_repo = Parameter( "GithubRepoLink", Description="Name of the repository you wish to connect to codebuild.", Type="String" ) artifact_key = Parameter( "ArtifactKey", Description="The key for the artifact that codebuild creates.", Type="String" ) t.add_parameter(github_repo) t.add_parameter(artifact_key) cms_code_build_project = codebuild.Project( "CMSBuild", t, Name="CMS-Build", Artifacts=codebuild.Artifacts( Location=Ref(app_bucket), Name=Ref(artifact_key), NamespaceType="BUILD_ID", Type="S3", Packaging="ZIP" ), Description="Code build for CMS", Environment=codebuild.Environment( ComputeType="BUILD_GENERAL1_SMALL", Image="aws/codebuild/python:3.6.5", Type="LINUX_CONTAINER", ), ServiceRole=GetAtt(codebuild_service_role, 'Arn'), Source=codebuild.Source( "CMSSourceCode", Auth=codebuild.SourceAuth( "GitHubAuth", Type="OAUTH" ), Location=Ref(github_repo), Type="GITHUB" ), Triggers=codebuild.ProjectTriggers( Webhook=True ) ) codedeploy_service_role = iam.Role( "CMSDeploymentGroupServiceRole", t, AssumeRolePolicyDocument={ 'Statement': [{ 'Effect': 'Allow', 'Principal': { 'Service': ['codedeploy.amazonaws.com'] }, 'Action': ['sts:AssumeRole'] }] }, Policies=[ iam.Policy( PolicyName="CloudWatchLogsPolicy", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Sid='logs', Effect=aws.Allow, Action=[ aws_logs.CreateLogGroup, aws_logs.CreateLogStream, aws_logs.PutLogEvents ], Resource=['*'] ) ] ) ), iam.Policy( PolicyName="s3AccessPolicy", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Sid='codebuilder', Effect=aws.Allow, Action=[ aws_s3.PutObject, aws_s3.GetObject, aws_s3.GetObjectVersion, aws_s3.DeleteObject ], Resource=[ GetAtt(app_bucket, 'Arn'), Join('', [ GetAtt(app_bucket, 'Arn'), '/*' ]) ] ) ] ) ), iam.Policy( PolicyName="autoscalingAccess", PolicyDocument=aws.Policy( Version="2012-10-17", Statement=[ aws.Statement( Sid='codebuilder', Effect=aws.Allow, Action=[ aws.Action('autoscaling', '*'), aws.Action('elasticloadbalancing', '*') ], Resource=[ '*' ] ) ] ) ) ] ) cms_codedeploy_application = codedeploy.Application( "CMSCodeDeployApplication", t, ) cms_deployment_group = codedeploy.DeploymentGroup( "CMSDeploymentGroup", t, DependsOn=[cms_codedeploy_application], ApplicationName=Ref(cms_codedeploy_application), AutoScalingGroups=[Ref(Web_autoscaler)], LoadBalancerInfo=codedeploy.LoadBalancerInfo( "CodeDeployLBInfo", TargetGroupInfoList=[ codedeploy.TargetGroupInfoList( "WebTargetGroup", Name=GetAtt(Web_target_group, "TargetGroupName") ) ] ), ServiceRoleArn=GetAtt(codedeploy_service_role, 'Arn') ) print(t.to_yaml())
def main(): # Initialize template template = Template() template.set_version("2010-09-09") template.set_description("""\ Configures autoscaling group for nginx app""") # Collect template properties through parameters InstanceType = template.add_parameter( Parameter( "InstanceType", Type="String", Description="WebServer EC2 instance type", Default="t2.small", AllowedValues=[ "t2.micro", "t2.small", "t2.medium", "t2.large", "t2.xlarge" ], ConstraintDescription="Must be a valid EC2 instance type.", )) KeyName = template.add_parameter( Parameter( "KeyName", Type="String", Description="Name of an existing EC2 KeyPair to enable SSH access", MinLength="1", AllowedPattern="[\x20-\x7E]*", MaxLength="255", ConstraintDescription="Can contain only ASCII characters.", )) ScaleCapacity = template.add_parameter( Parameter( "ScaleCapacity", Default="1", Type="String", Description="Number of nginx servers to run", )) PublicSubnet1 = template.add_parameter( Parameter( "PublicSubnet1", Type="String", Description= "A public VPC subnet ID for the nginx app load balancer.", )) PublicSubnet2 = template.add_parameter( Parameter( "PublicSubnet2", Type="String", Description="A public VPC subnet ID for the nginx load balancer.", )) VPCAvailabilityZone2 = template.add_parameter( Parameter( "VPCAvailabilityZone2", MinLength="1", Type="String", Description="Second availability zone", MaxLength="255", )) VPCAvailabilityZone1 = template.add_parameter( Parameter( "VPCAvailabilityZone1", MinLength="1", Type="String", Description="First availability zone", MaxLength="255", )) PrivateSubnet2 = template.add_parameter( Parameter( "PrivateSubnet2", Type="String", Description="Second private VPC subnet ID for the nginx app.", )) PrivateSubnet1 = template.add_parameter( Parameter( "PrivateSubnet1", Type="String", Description="First private VPC subnet ID for the nginx app.", )) VpcId = template.add_parameter( Parameter( "VpcId", Type="String", Description="VPC Id.", )) # as of now only provide centos based ami id AmiId = template.add_parameter( Parameter( "AmiId", Type="String", Description="AMI Id.", )) # Create a common security group NginxInstanceSG = template.add_resource( ec2.SecurityGroup( "InstanceSecurityGroup", VpcId=Ref(VpcId), GroupDescription="Enable SSH and HTTP access on the inbound port", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp="10.0.0.0/8", ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="80", ToPort="80", CidrIp="0.0.0.0/0", ) ])) # Add the application LB ApplicationElasticLB = template.add_resource( elb.LoadBalancer("ApplicationElasticLB", Name="ApplicationElasticLB", Scheme="internet-facing", Subnets=[Ref(PublicSubnet1), Ref(PublicSubnet2)], SecurityGroups=[Ref(NginxInstanceSG)])) # Add Target Group for the ALB TargetGroupNginx = template.add_resource( elb.TargetGroup( "TargetGroupNginx", VpcId=Ref(VpcId), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher(HttpCode="200"), Name="NginxTarget", Port="80", Protocol="HTTP", UnhealthyThresholdCount="3", )) # Add ALB listener Listener = template.add_resource( elb.Listener("Listener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(ApplicationElasticLB), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(TargetGroupNginx)) ])) # Add launch configuration for auto scaling LaunchConfig = template.add_resource( LaunchConfiguration( "LaunchConfiguration", ImageId=Ref(AmiId), KeyName=Ref(KeyName), AssociatePublicIpAddress="False", LaunchConfigurationName="nginx-LC", UserData=Base64( Join('', [ "#!/bin/bash\n", "yum update\n", "yum -y install nginx\n", "chkconfig nginx on\n", "service nginx start" ])), SecurityGroups=[Ref(NginxInstanceSG)], InstanceType=Ref(InstanceType))) # Add auto scaling group AutoscalingGroup = template.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=Ref(ScaleCapacity), LaunchConfigurationName=Ref(LaunchConfig), MinSize="1", TargetGroupARNs=[Ref(TargetGroupNginx)], MaxSize=Ref(ScaleCapacity), VPCZoneIdentifier=[Ref(PrivateSubnet1), Ref(PrivateSubnet2)], AvailabilityZones=[ Ref(VPCAvailabilityZone1), Ref(VPCAvailabilityZone2) ], HealthCheckType="EC2")) template.add_output( Output("URL", Description="URL of the sample website", Value=Join("", ["http://", GetAtt(ApplicationElasticLB, "DNSName")]))) #print(template.to_json()) with open('AutoScaling.yaml', 'w') as f: f.write(template.to_yaml())
def main(): template = Template() template.add_version("2010-09-09") template.add_description( "AWS CloudFormation Sample Template: ELB with 2 EC2 instances") AddAMI(template) # Add the Parameters keyname_param = template.add_parameter( Parameter( "KeyName", Type='AWS::EC2::KeyPair::KeyName', Default="ansible-key", Description="Name of an existing EC2 KeyPair to " "enable SSH access to the instance", )) template.add_parameter( Parameter( "InstanceType", Type="String", Description="WebServer EC2 instance type", Default="t2.micro", AllowedValues=["t1.micro", "t2.micro"], ConstraintDescription="must be a valid EC2 instance type.", )) webport_param = template.add_parameter( Parameter( "WebServerPort", Type="String", Default="8888", Description="TCP/IP port of the web server", )) web2_param = template.add_parameter( Parameter( "ApiServerPort", Type="String", Default="8889", Description="TCP/IP port of the api server", )) subnetA = template.add_parameter( Parameter("subnetA", Type="List<AWS::EC2::Subnet::Id>", Description="Choose Subnets")) VpcId = template.add_parameter( Parameter("VpcId", Type="AWS::EC2::VPC::Id", Description="Choose VPC")) # Define the instance security group instance_sg = template.add_resource( ec2.SecurityGroup( "InstanceSecurityGroup", GroupDescription="Enable SSH and HTTP access on the inbound port", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp="0.0.0.0/0", ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort=Ref(webport_param), ToPort=Ref(webport_param), CidrIp="0.0.0.0/0", ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort=Ref(web2_param), ToPort=Ref(web2_param), CidrIp="0.0.0.0/0", ), ])) # Add the web server instance WebInstance = template.add_resource( ec2.Instance( "WebInstance", SecurityGroups=[Ref(instance_sg)], KeyName=Ref(keyname_param), InstanceType=Ref("InstanceType"), ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), UserData=Base64( Join('', [ '#!/bin/bash\n', 'sudo yum -y update\n', 'sudo yum install -y httpd php\n', 'sudo sed -i "42s/Listen 80/Listen 8888/" /etc/httpd/conf/httpd.conf\n', 'sudo service httpd restart \n', 'Ref(webport_param)', ])))) # Add the api server instance ApiInstance = template.add_resource( ec2.Instance( "ApiInstance", SecurityGroups=[Ref(instance_sg)], KeyName=Ref(keyname_param), InstanceType=Ref("InstanceType"), ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), UserData=Base64( Join('', [ '#!/bin/bash\n', 'sudo yum -y update\n', 'sudo yum install -y httpd php\n', 'sudo sed -i "42s/Listen 80/Listen 8889/" /etc/httpd/conf/httpd.conf\n', 'sudo service httpd restart \n', 'Ref(web2_param)', ])))) # Add the application ELB ApplicationElasticLB = template.add_resource( elb.LoadBalancer("ApplicationElasticLB", Name="ApplicationElasticLB", Scheme="internet-facing", Subnets=Ref("subnetA"))) TargetGroupWeb = template.add_resource( elb.TargetGroup("TargetGroupWeb", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher(HttpCode="200"), Name="WebTarget", Port=Ref(webport_param), Protocol="HTTP", Targets=[ elb.TargetDescription(Id=Ref(WebInstance), Port=Ref(webport_param)) ], UnhealthyThresholdCount="3", VpcId=Ref(VpcId))) TargetGroupApi = template.add_resource( elb.TargetGroup("TargetGroupApi", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher(HttpCode="200"), Name="ApiTarget", Port=Ref(web2_param), Protocol="HTTP", Targets=[ elb.TargetDescription(Id=Ref(ApiInstance), Port=Ref(web2_param)) ], UnhealthyThresholdCount="3", VpcId=Ref(VpcId))) Listener = template.add_resource( elb.Listener("Listener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(ApplicationElasticLB), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(TargetGroupWeb)) ])) template.add_resource( elb.ListenerRule("ListenerRuleApi", ListenerArn=Ref(Listener), Conditions=[ elb.Condition(Field="path-pattern", Values=["/api/*"]) ], Actions=[ elb.Action(Type="forward", TargetGroupArn=Ref(TargetGroupApi)) ], Priority="1")) template.add_output( Output("URL", Description="URL of the sample website", Value=Join("", ["http://", GetAtt(ApplicationElasticLB, "DNSName")]))) print(template.to_json())
def buildStack(bootstrap, env): t = Template() t.add_description("""\ Configures autoscaling group for hello world app""") vpcCidr = t.add_parameter( Parameter( "VPCCidr", Type="String", Description="VPC cidr (x.x.x.x/xx)", )) publicSubnet1 = t.add_parameter( Parameter( "PublicSubnet1", Type="String", Description="A public VPC subnet ID for the api app load balancer.", )) publicSubnet2 = t.add_parameter( Parameter( "PublicSubnet2", Type="String", Description="A public VPC subnet ID for the api load balancer.", )) dbName = t.add_parameter( Parameter( "DBName", Default="HelloWorldApp", Description="The database name", Type="String", MinLength="1", MaxLength="64", AllowedPattern="[a-zA-Z][a-zA-Z0-9]*", ConstraintDescription=("must begin with a letter and contain only" " alphanumeric characters."))) dbUser = t.add_parameter( Parameter( "DBUser", NoEcho=True, Description="The database admin account username", Type="String", MinLength="1", MaxLength="16", AllowedPattern="[a-zA-Z][a-zA-Z0-9]*", ConstraintDescription=("must begin with a letter and contain only" " alphanumeric characters."))) dbPassword = t.add_parameter( Parameter( "DBPassword", NoEcho=True, Description="The database admin account password", Type="String", MinLength="8", MaxLength="41", AllowedPattern="[a-zA-Z0-9]*", ConstraintDescription="must contain only alphanumeric characters.") ) dbType = t.add_parameter( Parameter( "DBType", Default="db.t2.medium", Description="Database instance class", Type="String", AllowedValues=[ "db.m5.large", "db.m5.xlarge", "db.m5.2xlarge", "db.m5.4xlarge", "db.m5.12xlarge", "db.m5.24xlarge", "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", "db.x1e.xlarge", "db.x1e.2xlarge", "db.x1e.4xlarge", "db.x1e.8xlarge", "db.x1e.16xlarge", "db.x1e.32xlarge", "db.x1.16xlarge", "db.x1.32xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.t2.micro", "db.t2.small", "db.t2.medium", "db.t2.large", "db.t2.xlarge", "db.t2.2xlarge" ], ConstraintDescription="must select a valid database instance type.", )) dbAllocatedStorage = t.add_parameter( Parameter( "DBAllocatedStorage", Default="5", Description="The size of the database (Gb)", Type="Number", MinValue="5", MaxValue="1024", ConstraintDescription="must be between 5 and 1024Gb.", )) whitelistedCIDR = t.add_parameter( Parameter( "WhitelistedCIDR", Description="CIDR whitelisted to be open on public instances", Type="String", )) #### NETWORK SECTION #### vpc = t.add_resource( VPC("VPC", CidrBlock=Ref(vpcCidr), EnableDnsHostnames=True)) subnet1 = t.add_resource( Subnet("Subnet1", CidrBlock=Ref(publicSubnet1), AvailabilityZone="eu-west-1a", VpcId=Ref(vpc))) subnet2 = t.add_resource( Subnet("Subnet2", CidrBlock=Ref(publicSubnet2), AvailabilityZone="eu-west-1b", VpcId=Ref(vpc))) internetGateway = t.add_resource(InternetGateway('InternetGateway')) gatewayAttachment = t.add_resource( VPCGatewayAttachment('AttachGateway', VpcId=Ref(vpc), InternetGatewayId=Ref(internetGateway))) routeTable = t.add_resource(RouteTable('RouteTable', VpcId=Ref(vpc))) route = t.add_resource( Route( 'Route', DependsOn='AttachGateway', GatewayId=Ref('InternetGateway'), DestinationCidrBlock='0.0.0.0/0', RouteTableId=Ref(routeTable), )) subnetRouteTableAssociation = t.add_resource( SubnetRouteTableAssociation( 'SubnetRouteTableAssociation', SubnetId=Ref(subnet1), RouteTableId=Ref(routeTable), )) subnetRouteTableAssociation2 = t.add_resource( SubnetRouteTableAssociation( 'SubnetRouteTableAssociation2', SubnetId=Ref(subnet2), RouteTableId=Ref(routeTable), )) #### SECURITY GROUP #### loadBalancerSg = t.add_resource( ec2.SecurityGroup( "LoadBalancerSecurityGroup", VpcId=Ref(vpc), GroupDescription="Enable SSH access via port 22", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="80", ToPort="80", CidrIp="0.0.0.0/0", ), ], )) instanceSg = t.add_resource( ec2.SecurityGroup( "InstanceSecurityGroup", VpcId=Ref(vpc), GroupDescription="Enable SSH access via port 22", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp=Ref(whitelistedCIDR), ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="8000", ToPort="8000", SourceSecurityGroupId=Ref(loadBalancerSg), ), ], )) rdsSg = t.add_resource( SecurityGroup("RDSSecurityGroup", GroupDescription="Security group for RDS DB Instance.", VpcId=Ref(vpc), SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="5432", ToPort="5432", SourceSecurityGroupId=Ref(instanceSg), ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="5432", ToPort="5432", CidrIp=Ref(whitelistedCIDR), ), ])) #### DATABASE SECTION #### subnetGroup = t.add_resource( DBSubnetGroup( "SubnetGroup", DBSubnetGroupDescription= "Subnets available for the RDS DB Instance", SubnetIds=[Ref(subnet1), Ref(subnet2)], )) db = t.add_resource( DBInstance( "RDSHelloWorldApp", DBName=Join("", [Ref(dbName), env]), DBInstanceIdentifier=Join("", [Ref(dbName), env]), EnableIAMDatabaseAuthentication=True, PubliclyAccessible=True, AllocatedStorage=Ref(dbAllocatedStorage), DBInstanceClass=Ref(dbType), Engine="postgres", EngineVersion="10.4", MasterUsername=Ref(dbUser), MasterUserPassword=Ref(dbPassword), DBSubnetGroupName=Ref(subnetGroup), VPCSecurityGroups=[Ref(rdsSg)], )) t.add_output( Output("RDSConnectionString", Description="Connection string for database", Value=GetAtt("RDSHelloWorldApp", "Endpoint.Address"))) if (bootstrap): return t #### INSTANCE SECTION #### keyName = t.add_parameter( Parameter( "KeyName", Type="String", Description="Name of an existing EC2 KeyPair to enable SSH access", MinLength="1", AllowedPattern="[\x20-\x7E]*", MaxLength="255", ConstraintDescription="can contain only ASCII characters.", )) scaleCapacityMin = t.add_parameter( Parameter( "ScaleCapacityMin", Default="1", Type="String", Description="Number of api servers to run", )) scaleCapacityMax = t.add_parameter( Parameter( "ScaleCapacityMax", Default="1", Type="String", Description="Number of api servers to run", )) scaleCapacityDesired = t.add_parameter( Parameter( "ScaleCapacityDesired", Default="1", Type="String", Description="Number of api servers to run", )) amiId = t.add_parameter( Parameter( "AmiId", Type="String", Default="ami-09693313102a30b2c", Description="The AMI id for the api instances", )) instanceType = t.add_parameter( Parameter("InstanceType", Description="WebServer EC2 instance type", Type="String", Default="t2.medium", AllowedValues=[ "t2.nano", "t2.micro", "t2.small", "t2.medium", "t2.large", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge" ], ConstraintDescription="must be a valid EC2 instance type.")) assumeRole = t.add_resource( Role("AssumeRole", AssumeRolePolicyDocument=json.loads("""\ { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] }\ """))) instanceProfile = t.add_resource( InstanceProfile("InstanceProfile", Roles=[Ref(assumeRole)])) rolePolicyType = t.add_resource( PolicyType("RolePolicyType", Roles=[Ref(assumeRole)], PolicyName=Join("", ["CloudWatchHelloWorld", "-", env]), PolicyDocument=json.loads("""\ { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:DescribeLogStreams", "logs:PutLogEvents" ], "Effect": "Allow", "Resource": [ "arn:aws:logs:*:*:*" ] } ] }\ """))) appPassword = t.add_parameter( Parameter( "AppPassword", NoEcho=True, Description="The Password for the app user", Type="String", MinLength="8", MaxLength="41", AllowedPattern="[a-zA-Z0-9]*", ConstraintDescription="must contain only alphanumeric characters.") ) launchConfig = t.add_resource( LaunchConfiguration( "LaunchConfiguration", Metadata=autoscaling.Metadata( cloudformation.Init({ "config": cloudformation.InitConfig(files=cloudformation.InitFiles({ "/home/app/environment": cloudformation.InitFile(content=Join( "", [ "SPRING_DATASOURCE_URL=", "jdbc:postgresql://", GetAtt("RDSHelloWorldApp", "Endpoint.Address"), ":5432/HelloWorldApp" + env + "?currentSchema=hello_world", "\n", "SPRING_DATASOURCE_USERNAME=app", "\n", "SPRING_DATASOURCE_PASSWORD="******"\n", "SPRING_PROFILES_ACTIVE=", env, "\n" ]), mode="000600", owner="app", group="app") }), ) }), ), UserData=Base64( Join('', [ "#!/bin/bash\n", "/opt/aws/bin/cfn-init", " --resource LaunchConfiguration", " --stack ", Ref("AWS::StackName"), " --region ", Ref("AWS::Region"), "\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref": "AWS::StackName" }, " --resource AutoscalingGroup ", " --region ", { "Ref": "AWS::Region" }, "\n" ])), ImageId=Ref(amiId), KeyName=Ref(keyName), IamInstanceProfile=Ref(instanceProfile), BlockDeviceMappings=[ ec2.BlockDeviceMapping(DeviceName="/dev/xvda", Ebs=ec2.EBSBlockDevice(VolumeSize="8")), ], SecurityGroups=[Ref(instanceSg)], InstanceType=Ref(instanceType), AssociatePublicIpAddress='True', )) applicationElasticLB = t.add_resource( elb.LoadBalancer("ApplicationElasticLB", Name="ApplicationElasticLB-" + env, Scheme="internet-facing", Type="application", SecurityGroups=[Ref(loadBalancerSg)], Subnets=[Ref(subnet1), Ref(subnet2)])) targetGroup = t.add_resource( elb.TargetGroup("TargetGroupHelloWorld", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="15", HealthyThresholdCount="5", Matcher=elb.Matcher(HttpCode="200,404"), Port="8000", Protocol="HTTP", UnhealthyThresholdCount="3", TargetGroupAttributes=[ elb.TargetGroupAttribute( Key="deregistration_delay.timeout_seconds", Value="120", ) ], VpcId=Ref(vpc))) listener = t.add_resource( elb.Listener("Listener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(applicationElasticLB), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(targetGroup)) ])) t.add_output( Output("URL", Description="URL of the sample website", Value=Join("", ["http://", GetAtt(applicationElasticLB, "DNSName")]))) autoScalingGroup = t.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=Ref(scaleCapacityDesired), LaunchConfigurationName=Ref(launchConfig), MinSize=Ref(scaleCapacityMin), MaxSize=Ref(scaleCapacityMax), VPCZoneIdentifier=[Ref(subnet1), Ref(subnet2)], TargetGroupARNs=[Ref(targetGroup)], HealthCheckType="ELB", HealthCheckGracePeriod=360, UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)), CreationPolicy=CreationPolicy(ResourceSignal=ResourceSignal( Timeout="PT15M", Count=Ref(scaleCapacityDesired))))) # print(t.to_json()) return t
def main(): # Meta t.add_version("2010-09-09") t.add_description("Template for auto-scaling in an Application" "load balancer target group. " "The ALB will be used as an A Alias target " "for a specified Route53 hosted zone. " "This template also showcases " "Metadata Parameter Grouping, " "Special AWS Parameter Types, " "and Cloudformation Outputs with Exports" "which can be imported into other templates.") t.add_metadata({ "Author": "https://github.com/hmain/", "LastUpdated": "2017 01 31", "Version": "1", }) # Parameter grouping t.add_metadata({ "AWS::CloudFormation::Interface": { "ParameterGroups": [{ "Label": { "default": "Global parameters" }, "Parameters": ["environment"] }, { "Label": { "default": "Application Loadbalancer" }, "Parameters": [ "albSubnets", "loadbalancerPrefix", "loadBalancerArn", "albPaths", "albPort" ] }, { "Label": { "default": "VPC" }, "Parameters": ["ec2Subnets", "VPC", "securityGroup"] }, { "Label": { "default": "EC2" }, "Parameters": ["ec2Name", "ec2Type", "ec2Key"] }, { "Label": { "default": "Auto-scaling" }, "Parameters": [ "asgCapacity", "asgMinSize", "asgMaxSize", "asgCooldown", "asgHealthGrace" ] }, { "Label": { "default": "Route53" }, "Parameters": ["route53HostedZoneId", "route53HostedZoneName"] }] } }) AddAMI(t) environment = t.add_parameter( Parameter( "environment", Default="dev", Type="String", Description="Development or Production environment", AllowedValues=["dev", "prod"], ConstraintDescription="dev or prod", )) route53_hosted_zone_id = t.add_parameter( Parameter("route53HostedZoneId", Default="", Type="AWS::Route53::HostedZone::Id", Description="Route53 DNS zone ID")) route53_hosted_zone_name = t.add_parameter( Parameter("route53HostedZoneName", Default="my.aws.dns.com", Type="String", Description="Route53 hosted zone name")) security_group = t.add_parameter( Parameter("securityGroup", Default="", Type="List<AWS::EC2::SecurityGroup::Id>", Description="Which security groups to use")) alb_paths = t.add_parameter( Parameter( "albPaths", Default="/", Type="CommaDelimitedList", Description="Path-patterns you want the loadbalancer to point to in " "your application")) albPort = t.add_parameter( Parameter("albPort", Default="80", Type="Number", Description="Which loadbalancer port to use")) ec2_subnets = t.add_parameter( Parameter("ec2Subnets", Default="", Type="List<AWS::EC2::Subnet::Id>", Description="Private subnets for the instances.")) alb_subnets = t.add_parameter( Parameter("albSubnets", Default="", Type="List<AWS::EC2::Subnet::Id>", Description="Public subnets for the load balancer.")) loadbalancer_prefix = t.add_parameter( Parameter( "loadbalancerPrefix", Default="", Type="String", Description="Specify a prefix for your loadbalancer", )) vpc = t.add_parameter( Parameter("VPC", Default="", Type="AWS::EC2::VPC::Id", Description="Environment VPC")) # Auto scaling group parameters asg_capacity = t.add_parameter( Parameter("asgCapacity", Default="0", Type="Number", Description="Number of instances")) asg_min_size = t.add_parameter( Parameter("asgMinSize", Default="0", Type="Number", Description="Minimum size of AutoScalingGroup")) asg_max_size = t.add_parameter( Parameter("asgMaxSize", Default="1", Type="Number", Description="Maximum size of AutoScalingGroup")) asg_cooldown = t.add_parameter( Parameter( "asgCooldown", Default="300", Type="Number", Description="Cooldown before starting/stopping another instance")) asg_health_grace = t.add_parameter( Parameter( "asgHealthGrace", Default="300", Type="Number", Description="Wait before starting/stopping another instance")) # EC2 parameters ec2_name = t.add_parameter( Parameter("ec2Name", Default="myApplication", Type="String", Description="Name of the instances")) ec2_type = t.add_parameter( Parameter("ec2Type", Default="t2.large", Type="String", Description="Instance type.")) ec2_key = t.add_parameter( Parameter("ec2Key", Default="", Type="AWS::EC2::KeyPair::KeyName", Description="EC2 Key Pair")) # Launchconfiguration ec2_launchconfiguration = t.add_resource( autoscaling.LaunchConfiguration( "EC2LaunchConfiguration", ImageId=FindInMap("windowsAMI", Ref("AWS::Region"), "AMI"), KeyName=Ref(ec2_key), SecurityGroups=Ref(security_group), InstanceType=Ref(ec2_type), AssociatePublicIpAddress=False, )) # Application ELB alb_target_group = t.add_resource( elb.TargetGroup("albTargetGroup", HealthCheckPath=Select("0", Ref(alb_paths)), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher(HttpCode="200"), Name=Ref(ec2_name), Port=80, Protocol="HTTP", UnhealthyThresholdCount="3", VpcId=Ref(vpc))) # Auto scaling group t.add_resource( autoscaling.AutoScalingGroup( "autoScalingGroup", DesiredCapacity=Ref(asg_capacity), Tags=autoscaling.Tags(Environment=Ref(environment)), VPCZoneIdentifier=Ref(ec2_subnets), TargetGroupARNs=[Ref(alb_target_group)], MinSize=Ref(asg_min_size), MaxSize=Ref(asg_max_size), Cooldown=Ref(asg_cooldown), LaunchConfigurationName=Ref(ec2_launchconfiguration), HealthCheckGracePeriod=Ref(asg_health_grace), HealthCheckType="EC2", )) # Application Load Balancer application_load_balancer = t.add_resource( elb.LoadBalancer("applicationLoadBalancer", Name=Ref(loadbalancer_prefix), Scheme="internet-facing", Subnets=Ref(alb_subnets), SecurityGroups=Ref(security_group))) alb_listener = t.add_resource( elb.Listener("albListener", Port=Ref(albPort), Protocol="HTTP", LoadBalancerArn=Ref(application_load_balancer), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(alb_target_group)) ])) t.add_resource( elb.ListenerRule("albListenerRule", ListenerArn=Ref(alb_listener), Conditions=[ elb.Condition(Field="path-pattern", Values=Ref(alb_paths)) ], Actions=[ elb.Action(Type="forward", TargetGroupArn=Ref(alb_target_group)) ], Priority="1")) # Route53 t.add_resource( route53.RecordSetGroup( "route53RoundRobin", HostedZoneId=Ref(route53_hosted_zone_id), RecordSets=[ route53.RecordSet( Weight=1, SetIdentifier=Join(".", [ Ref(environment), Ref(route53_hosted_zone_name), "ELB" ]), Name=Join( ".", [Ref(environment), Ref(route53_hosted_zone_name)]), Type="A", AliasTarget=route53.AliasTarget( GetAtt(application_load_balancer, "CanonicalHostedZoneID"), GetAtt(application_load_balancer, "DNSName"))) ])) t.add_output( Output( "URL", Description="URL of the website", Value=Join("", [ "http://", GetAtt(application_load_balancer, "DNSName"), Select("0", Ref(alb_paths)) ]), Export=Export(Sub("${AWS::StackName}-URL")), )) print(t.to_json())
# Create the ALB ALB = t.add_resource(elasticloadbalancingv2.LoadBalancer( "ALB", Scheme="internet-facing", Subnets=[Ref(PubSubnetAz1), Ref(PubSubnetAz2)], SecurityGroups=[Ref(ALBSecurityGroup)] )) # Create the ALB"s Target Group ALBTargetGroup = t.add_resource(elasticloadbalancingv2.TargetGroup( "ALBTargetGroup", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elasticloadbalancingv2.Matcher( HttpCode="200"), Port=80, Protocol="HTTP", UnhealthyThresholdCount="3", TargetType="ip", VpcId=Ref(VPC) )) ALBListener = t.add_resource(elasticloadbalancingv2.Listener( "ALBListener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(ALB), DefaultActions=[elasticloadbalancingv2.Action( Type="forward", TargetGroupArn=Ref(ALBTargetGroup)
def generate_template(d): # Set template metadata t = Template() t.add_version("2010-09-09") t.set_description(d["cf_template_description"]) aws_account_id = Ref("AWS::AccountId") aws_region = Ref("AWS::Region") # Task definition task_definition = t.add_resource( TaskDefinition( "TaskDefinition", Family=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), RequiresCompatibilities=["FARGATE"], Cpu=d["container_cpu"], Memory=d["container_memory"], NetworkMode="awsvpc", ExecutionRoleArn=ImportValue(d["ecs_stack_name"] + "-ECSClusterRole"), ContainerDefinitions=[ ContainerDefinition( Name=Join("", [ d["env"], "-", d["project_name"], "-", d["service_name"] ]), Image=Join( "", [ aws_account_id, ".dkr.ecr.", aws_region, ".amazonaws.com/", d["env"], d["project_name"], d["service_name"], ":latest" ], ), Essential=True, PortMappings=[ PortMapping( ContainerPort=d["container_port"], HostPort=d["container_port"], ) ], EntryPoint=["sh", "-c"], Command=[d["container_command"]], LogConfiguration=LogConfiguration( LogDriver="awslogs", Options={ "awslogs-region": aws_region, "awslogs-group": Join("", [ d["env"], "-", d["project_name"], "-", d["service_name"] ]), "awslogs-stream-prefix": "ecs", "awslogs-create-group": "true" })) ], Tags=Tags(d["tags"], {"Name": d["project_name"] + "-task-definition"}), )) # ECR ecr = t.add_resource( Repository( "ECR", DependsOn="ListenerRule", RepositoryName=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecr"}), )) # Target group target_group = t.add_resource( elb.TargetGroup( "TargetGroup", Name=Join("", [d["env"], "-", d["service_name"]]), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckPort=d["container_port"], HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", HealthCheckPath=d["tg_health_check_path"], Matcher=elb.Matcher(HttpCode="200-299"), Port=d["container_port"], Protocol="HTTP", TargetType="ip", UnhealthyThresholdCount="3", VpcId=ImportValue(d["network_stack_name"] + "-VPCId"), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecr"}), )) # Listener rule t.add_resource( elb.ListenerRule( "ListenerRule", DependsOn="TargetGroup", ListenerArn=ImportValue(d["ecs_stack_name"] + "-ListenerArnHTTP"), Conditions=[ elb.Condition(Field="path-pattern", Values=[d["application_path_api"]]) ], Actions=[ elb.Action(Type="forward", TargetGroupArn=Ref(target_group)) ], Priority="1", )) # ECS service ecs_service = t.add_resource( Service( "ECSService", ServiceName=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), DependsOn="pipeline", DesiredCount=d["container_desired_tasks_count"], TaskDefinition=Ref(task_definition), LaunchType="FARGATE", NetworkConfiguration=NetworkConfiguration( AwsvpcConfiguration=AwsvpcConfiguration( Subnets=[ ImportValue(d["network_stack_name"] + "-PrivateSubnetId1"), ImportValue(d["network_stack_name"] + "-PrivateSubnetId2"), ], SecurityGroups=[ ImportValue(d["ecs_stack_name"] + "-ECSClusterSG") ], )), LoadBalancers=([ LoadBalancer( ContainerName=Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"] ], ), ContainerPort=d["container_port"], TargetGroupArn=Ref(target_group), ) ]), Cluster=ImportValue(d["ecs_stack_name"] + "-ECSClusterName"), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-ecs-service"}), )) # App Autoscaling target # App Autoscaling policy # Codebuild project codebuild = t.add_resource( Project( "codebuild", Name=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), DependsOn="ECR", ServiceRole=ImportValue(d["ecs_stack_name"] + "-CodebuildDeveloperRole"), Artifacts=Artifacts( Name="Build", Location=d["artifact_store"], Type="S3", ), Description="Build a docker image and send it to ecr", Source=Source( BuildSpec="buildspec.yml", Type="S3", Location=d["artifact_store"] + "/" + d["artifact_name"], ), Environment=Environment( ComputeType="BUILD_GENERAL1_SMALL", Image="aws/codebuild/standard:4.0", PrivilegedMode=True, Type="LINUX_CONTAINER", EnvironmentVariables=[ EnvironmentVariable( Name="AWS_DEFAULT_REGION", Type="PLAINTEXT", Value=aws_region, ), EnvironmentVariable( Name="SERVICE_NAME", Type="PLAINTEXT", Value=Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"] ], ), ), EnvironmentVariable( Name="IMAGE_URI", Type="PLAINTEXT", Value=Join( "", [ aws_account_id, ".dkr.ecr.", aws_region, ".amazonaws.com/", d["env"], "-", d["project_name"], "-", d["service_name"], ], ), ), ], ), Tags=Tags(d["tags"], {"Name": d["project_name"] + "-codebuild"}), )) # Codepipeline pipeline = t.add_resource( Pipeline( "pipeline", Name=Join( "", [d["env"], "-", d["project_name"], "-", d["service_name"]]), RoleArn=ImportValue(d["ecs_stack_name"] + "-CodePipelineRole"), Stages=[ Stages( Name="Source", Actions=[ Actions( Name="Source", ActionTypeId=ActionTypeId( Category="Source", Owner="AWS", Version="1", Provider="S3", ), OutputArtifacts=[ OutputArtifacts(Name="source_artifact") ], Configuration={ "S3Bucket": d["artifact_store"], "S3ObjectKey": d["artifact_name"], }, RunOrder="1", ) ], ), Stages( Name="Build", Actions=[ Actions( Name="Build", InputArtifacts=[ InputArtifacts(Name="source_artifact") ], OutputArtifacts=[ OutputArtifacts(Name="build_artifact") ], ActionTypeId=ActionTypeId( Category="Build", Owner="AWS", Version="1", Provider="CodeBuild", ), Configuration={"ProjectName": Ref(codebuild)}, RunOrder="1", ) ], ), Stages( Name="Deploy", Actions=[ Actions( Name="Deploy", InputArtifacts=[ InputArtifacts(Name="build_artifact") ], ActionTypeId=ActionTypeId( Category="Deploy", Owner="AWS", Version="1", Provider="ECS", ), Configuration={ "ClusterName": ImportValue(d["ecs_stack_name"] + "-ECSClusterName"), "ServiceName": Join( "", [ d["env"], "-", d["project_name"], "-", d["service_name"], ], ), "FileName": "definitions.json", }, ) ], ), ], ArtifactStore=ArtifactStore(Type="S3", Location=d["artifact_store"]), )) # Route53 # Outputs return t
Protocol='HTTP', Port='80', Targets=[ elbv2.TargetDescription( Id=Ref(param_instance_id), Port='80', ) ], HealthCheckIntervalSeconds='15', HealthCheckPath='/', HealthCheckPort='80', HealthCheckProtocol='HTTP', HealthCheckTimeoutSeconds='5', HealthyThresholdCount='3', UnhealthyThresholdCount='5', Matcher=elbv2.Matcher(HttpCode='200'), TargetGroupAttributes=[ elbv2.TargetGroupAttribute( Key='deregistration_delay.timeout_seconds', Value='20') ])) http_listener = t.add_resource( elbv2.Listener( 'HttpListener', DefaultActions=[ elbv2.Action(TargetGroupArn=Ref(targetgroup), Type='forward') ], LoadBalancerArn=Ref(load_balancer), Port='80', Protocol='HTTP',
def elbv2_target_group(self, name, protocol, port, vpc_id, health_check_details={}, matcher=None, target_group_attributes=False, targets=[]): """ Create ELBv2 Target Group :param name: Name of the target group :param protocol: Protocol :param port: Port :param vpc_id: VPC id :param health_check_details: Array of health check detail :param matcher: HTTP code to use when checking for health check response :param target_group_attributes: Additional target group attributes :param targets: Targets, if applicable :return: Target Group CFN object """ target_group = elbv2.TargetGroup( name, Protocol=protocol, Port=port, VpcId=vpc_id, HealthCheckProtocol=health_check_details["health_check_protocol"], HealthCheckPort=health_check_details["health_check_port"], HealthCheckIntervalSeconds=health_check_details[ "health_check_interval"], HealthyThresholdCount=health_check_details["healthy_threshold"], UnhealthyThresholdCount=health_check_details[ "unhealthy_threshold"], Targets=targets) if health_check_details.get("health_check_path"): target_group.HealthCheckPath = health_check_details[ "health_check_path"] if health_check_details.get("health_check_timeout"): target_group.HealthCheckTimeoutSeconds = health_check_details[ "health_check_timeout"] if matcher: target_group.Matcher = elbv2.Matcher(HttpCode=matcher) if target_group_attributes: attributes = [] for attr in target_group_attributes: attributes.append( elbv2.TargetGroupAttribute(Key=attr['key'], Value=attr['value'])) target_group.TargetGroupAttributes = attributes self.template.add_resource(target_group) self.template.add_output( Output(name, Value=Ref(name), Description="Target Group {} ARN".format(name), Export=Export(Sub("${AWS::StackName}-" + name)))) return target_group
def define_load_balancer(template, sg): alb_target_group_80 = elb.TargetGroup( stack_name_strict + "TG80", Tags=Tags(Name=stack_name, Custo=app_name), HealthCheckPath=Ref(alb_health_check_path), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="3", Matcher=elb.Matcher(HttpCode="301"), Port=80, Protocol="HTTP", UnhealthyThresholdCount="2", VpcId=Ref(vpc_id)) template.add_resource(alb_target_group_80) alb_target_group_9090 = elb.TargetGroup( stack_name_strict + "TG9090", Tags=Tags(Name=stack_name, Custo=app_name), HealthCheckPath=Ref(alb_health_check_path), HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="3", Matcher=elb.Matcher(HttpCode="200"), Port=9090, Protocol="HTTP", UnhealthyThresholdCount="2", VpcId=Ref(vpc_id)) template.add_resource(alb_target_group_9090) alb = elb.LoadBalancer(stack_name_strict + "ALB", Tags=Tags(Name=stack_name, Custo=app_name), Scheme="internet-facing", Subnets=[Ref(subnet_id1), Ref(subnet_id2)], SecurityGroups=[Ref(sg)]) template.add_resource(alb) alb_listener_80 = elb.Listener( stack_name_strict + "ListenerALB80", Port=80, Protocol="HTTP", LoadBalancerArn=Ref(alb), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(alb_target_group_80)) ]) template.add_resource(alb_listener_80) alb_listener_443 = elb.Listener( stack_name_strict + "ListenerALB443", Port=443, Protocol="HTTPS", Certificates=[ elb.Certificate(CertificateArn=Ref(ssl_certificate_arn)) ], LoadBalancerArn=Ref(alb), DefaultActions=[ elb.Action(Type="forward", TargetGroupArn=Ref(alb_target_group_9090)) ]) template.add_resource(alb_listener_443) return { "loadbalancer": alb, "alb_target_group_80": alb_target_group_80, "alb_target_group_9090": alb_target_group_9090, "alb_listener_80": alb_listener_80, "alb_listener_9090": alb_listener_443 }
def main(): template = Template() template.add_version("2010-09-09") template.add_description( "AWS CloudFormation Sample Template: ELB with 2 EC2 instances") AddAMI(template) # Add the Parameters keyname_param = template.add_parameter(Parameter( "KeyName", Type="String", Default="mark", Description="Name of an existing EC2 KeyPair to " "enable SSH access to the instance", )) template.add_parameter(Parameter( "InstanceType", Type="String", Description="WebServer EC2 instance type", Default="m1.small", AllowedValues=[ "t1.micro", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.medium", "c1.xlarge", "cc1.4xlarge", "cc2.8xlarge", "cg1.4xlarge" ], ConstraintDescription="must be a valid EC2 instance type.", )) webport_param = template.add_parameter(Parameter( "WebServerPort", Type="String", Default="8888", Description="TCP/IP port of the web server", )) apiport_param = template.add_parameter(Parameter( "ApiServerPort", Type="String", Default="8889", Description="TCP/IP port of the api server", )) subnetA = template.add_parameter(Parameter( "subnetA", Type="String", Default="subnet-096fd06d" )) subnetB = template.add_parameter(Parameter( "subnetB", Type="String", Default="subnet-1313ef4b" )) VpcId = template.add_parameter(Parameter( "VpcId", Type="String", Default="vpc-82c514e6" )) # Define the instance security group instance_sg = template.add_resource( ec2.SecurityGroup( "InstanceSecurityGroup", GroupDescription="Enable SSH and HTTP access on the inbound port", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp="0.0.0.0/0", ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort=Ref(webport_param), ToPort=Ref(webport_param), CidrIp="0.0.0.0/0", ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort=Ref(apiport_param), ToPort=Ref(apiport_param), CidrIp="0.0.0.0/0", ), ] ) ) # Add the web server instance WebInstance = template.add_resource(ec2.Instance( "WebInstance", SecurityGroups=[Ref(instance_sg)], KeyName=Ref(keyname_param), InstanceType=Ref("InstanceType"), ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), UserData=Base64(Ref(webport_param)), )) # Add the api server instance ApiInstance = template.add_resource(ec2.Instance( "ApiInstance", SecurityGroups=[Ref(instance_sg)], KeyName=Ref(keyname_param), InstanceType=Ref("InstanceType"), ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), UserData=Base64(Ref(apiport_param)), )) # Add the application ELB ApplicationElasticLB = template.add_resource(elb.LoadBalancer( "ApplicationElasticLB", Name="ApplicationElasticLB", Scheme="internet-facing", Subnets=[Ref(subnetA), Ref(subnetB)] )) TargetGroupWeb = template.add_resource(elb.TargetGroup( "TargetGroupWeb", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher( HttpCode="200"), Name="WebTarget", Port=Ref(webport_param), Protocol="HTTP", Targets=[elb.TargetDescription( Id=Ref(WebInstance), Port=Ref(webport_param))], UnhealthyThresholdCount="3", VpcId=Ref(VpcId) )) TargetGroupApi = template.add_resource(elb.TargetGroup( "TargetGroupApi", HealthCheckIntervalSeconds="30", HealthCheckProtocol="HTTP", HealthCheckTimeoutSeconds="10", HealthyThresholdCount="4", Matcher=elb.Matcher( HttpCode="200"), Name="ApiTarget", Port=Ref(apiport_param), Protocol="HTTP", Targets=[elb.TargetDescription( Id=Ref(ApiInstance), Port=Ref(apiport_param))], UnhealthyThresholdCount="3", VpcId=Ref(VpcId) )) Listener = template.add_resource(elb.Listener( "Listener", Port="80", Protocol="HTTP", LoadBalancerArn=Ref(ApplicationElasticLB), DefaultActions=[elb.Action( Type="forward", TargetGroupArn=Ref(TargetGroupWeb) )] )) template.add_resource(elb.ListenerRule( "ListenerRuleApi", ListenerArn=Ref(Listener), Conditions=[elb.Condition( Field="path-pattern", Values=["/api/*"])], Actions=[elb.Action( Type="forward", TargetGroupArn=Ref(TargetGroupApi) )], Priority="1" )) template.add_output(Output( "URL", Description="URL of the sample website", Value=Join("", ["http://", GetAtt(ApplicationElasticLB, "DNSName")]) )) print(template.to_json())
def generate_app_load_balancer(self, lb_name, typ, port, cert_arn, log_bucket): lb_name = self.cfn_name(lb_name) if len(lb_name) >= 32: alb_name = lb_name[0:31] else: alb_name = lb_name if len(lb_name + 'TG') >= 32: tg_name = '{}TG'.format(lb_name[0:29]) else: tg_name = '{}TG'.format(lb_name) if typ not in ['internal', 'internet-facing']: raise NameError("Load balancer type must be of type internal, internet-facing") # Use the system security groups (automatic) if internal, else use the limited external security group sg = self.security_groups if typ == 'internal' else [Ref(self.elb_external_security_group)] _alb = elasticloadbalancingv2.LoadBalancer( alb_name, Name=alb_name, IpAddressType='ipv4', LoadBalancerAttributes=[ elasticloadbalancingv2.LoadBalancerAttributes( Key='access_logs.s3.enabled', Value='true' ), elasticloadbalancingv2.LoadBalancerAttributes( Key='access_logs.s3.bucket', Value=log_bucket ), elasticloadbalancingv2.LoadBalancerAttributes( Key='access_logs.s3.prefix', Value="ELB/{}/{}".format(self.env, lb_name) ), elasticloadbalancingv2.LoadBalancerAttributes( Key='deletion_protection.enabled', Value='false' ), elasticloadbalancingv2.LoadBalancerAttributes( Key='idle_timeout.timeout_seconds', Value='60' ), elasticloadbalancingv2.LoadBalancerAttributes( Key='routing.http.drop_invalid_header_fields.enabled', Value='false' ), elasticloadbalancingv2.LoadBalancerAttributes( Key='routing.http2.enabled', Value='true' ) ], Scheme=typ, SecurityGroups=sg, Subnets=[s['SubnetId'] for s in self.get_subnets('private' if typ == 'internal' else 'public')], Type='application', Tags=self.get_tags( service_override="InternalALB" if typ == 'internal' else "ExternalALB", role_override=lb_name ) + [ec2.Tag('Name', lb_name)] ) _target_group = elasticloadbalancingv2.TargetGroup( tg_name, Name=tg_name, HealthCheckIntervalSeconds=30, HealthCheckPath='/ping', HealthCheckPort=port, HealthCheckProtocol='HTTP', HealthCheckTimeoutSeconds=5, HealthyThresholdCount=5, UnhealthyThresholdCount=2, Matcher=elasticloadbalancingv2.Matcher( HttpCode='200' ), Port=port, Protocol='HTTP', TargetGroupAttributes=[ elasticloadbalancingv2.TargetGroupAttribute( Key='deregistration_delay.timeout_seconds', Value='300' ), elasticloadbalancingv2.TargetGroupAttribute( Key='stickiness.enabled', Value='false' ), elasticloadbalancingv2.TargetGroupAttribute( Key='stickiness.type', Value='lb_cookie' ), elasticloadbalancingv2.TargetGroupAttribute( Key='load_balancing.algorithm.type', Value='least_outstanding_requests' ) ], TargetType='instance', VpcId=self.vpc_id, Tags=self.get_tags( service_override="InternalALB" if typ == 'internal' else "ExternalALB", role_override=lb_name ) + [ec2.Tag('Name', '{}TG'.format(lb_name))] ) _listener_80 = self.add_resource(elasticloadbalancingv2.Listener( '{}80Listener'.format(lb_name), Port='80', Protocol='HTTP', LoadBalancerArn=Ref(_alb), DefaultActions=[ elasticloadbalancingv2.Action( Type='redirect', RedirectConfig=elasticloadbalancingv2.RedirectConfig( Host='#{host}', Path='/#{path}', Port='443', Protocol='HTTPS', Query='#{query}', StatusCode='HTTP_301' ) ) ], )) _listener_443 = self.add_resource(elasticloadbalancingv2.Listener( '{}443Listener'.format(lb_name), Port='443', Protocol='HTTPS', LoadBalancerArn=Ref(_alb), SslPolicy='ELBSecurityPolicy-2016-08', Certificates=[ elasticloadbalancingv2.Certificate( CertificateArn=cert_arn ) ], DefaultActions=[ elasticloadbalancingv2.Action( Type='forward', TargetGroupArn=Ref(_target_group) ) ], )) return _alb, _target_group