{ "AWSTemplateFormatVersion":"2010-09-09", "Description":"Builds a S3 bucket, a VPC w/ 1 public subnet, an IGW, route tables, ACL, 1 EC2 instance for Jenkins, and CodePipeline.", "Parameters":{ "KeyName":{ "Description":"Name of an existing EC2 KeyPair for SSH access to the instances.", "Type":"AWS::EC2::KeyPair::KeyName" }, "AppName":{ "Type":"String", "Description":"Name of the application.", "MinLength":"2", "MaxLength":"15", "Default":"app-name", "AllowedPattern":"[a-z0-9][-. a-z0-9]*", "ConstraintDescription":"Must be between 2 and 15 characters long, lowercase and may contain alphanumeric characters, hyphens (-), and dots (.), but must start with alphanumeric." }, "S3ArtifactObject":{ "Type":"String", "Default":"public/jenkins/aws-codepipeline-s3-aws-codedeploy-linux-pmd.zip", "Description":"Application artfiact name in S3." }, "S3ArtifactBucket":{ "Type":"String", "Default":"stelligent-training-public", "Description":"Name of the bucket that the application artifact will be based in." }, "YourIP":{ "Description":"IP address to connect to SSH from. Check http://checkip.amazonaws.com/ to find yours.", "Type":"String", "Default":"999.999.999.999/32", "MinLength":"10", "MaxLength":"18", "AllowedPattern":"(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription":"must be a valid IP CIDR range of the form x.x.x.x/x." }, "RepositoryName":{ "Description":"The name of the CodeCommit repo", "Type":"String", "AllowedPattern":"[\\x20-\\x7E]*", "ConstraintDescription":"Can contain only ASCII characters." }, "RepositoryBranch":{ "Description":"The name of the branch for the CodeCommit repo", "Type":"String", "Default":"master", "AllowedPattern":"[\\x20-\\x7E]*", "ConstraintDescription":"Can contain only ASCII characters." }, "ECSRepoName":{ "Type":"String", "Description":"The name of the ECR Repo" }, "ECSCFNURL":{ "Type":"String", "Default":"NOURL", "Description":"The URL for this CloudFormation Template" }, "ImageTag":{ "Type":"String", "Description":"The version of the image tag", "Default":"latest" }, "DesiredCapacity":{ "Type":"Number", "Default":"1", "Description":"Number of instances to launch in your ECS cluster" }, "MaxSize":{ "Type":"Number", "Default":"1", "Description":"Maximum number of instances that can be launched in your ECS cluster" }, "InstanceType":{ "Description":"The EC2 instance type", "Type":"String", "Default":"t2.micro", "AllowedValues":[ "t2.micro", "t2.small", "t2.medium", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "d2.xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge" ], "ConstraintDescription":"must be a valid EC2 instance type." }, "SSHLocation":{ "Description":" The IP address range that can be used to SSH to the EC2 instances", "Type":"String", "MinLength":"9", "MaxLength":"18", "Default":"0.0.0.0/0", "AllowedPattern":"(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription":"must be a valid IP CIDR range of the form x.x.x.x/x." } }, "Metadata":{ "AWS::CloudFormation::Interface":{ "ParameterGroups":[ { "Label":{ "default":"Dynamic Configuration" }, "Parameters":[ "KeyName", "YourIP", "ECSRepoName", "RepositoryName" ] }, { "Label":{ "default":"ECS Configuration" }, "Parameters":[ "DesiredCapacity", "ImageTag", "MaxSize" ] }, { "Label":{ "default":"CodeCommit Configuration" }, "Parameters":[ "RepositoryBranch" ] } ] } }, "Mappings":{ "VPCIpSpace":{ "us-east-1":{ "RANGE":"10.52" }, "us-west-2":{ "RANGE":"10.53" } }, "SubnetTypeIpRanges":{ "public":{ "RANGE":"0.0/17" } }, "publicSubnetConfig":{ "publicSubnet01":{ "CIDR":"10.0/24" }, "publicSubnet02":{ "CIDR":"2.0/24" } }, "instancesTypes":{ "Demo":{ "INST":"t2.small" } }, "AWSInstanceType2Virt":{ "t2.micro":{ "Virt":"HVM" }, "t2.small":{ "Virt":"HVM" }, "t2.medium":{ "Virt":"HVM" }, "t2.large":{ "Virt":"HVM" } }, "AWSInstanceType2EBSOpt":{ "t2.micro":{ "EBSOpt":"false" }, "t2.small":{ "EBSOpt":"false" }, "t2.medium":{ "EBSOpt":"false" }, "t2.large":{ "EBSOpt":"false" } }, "AWSRegionVirt2AMI":{ "us-east-1":{ "HVM":"ami-8fcee4e5" }, "us-west-2":{ "HVM":"ami-63b25203" } }, "AWSRegionToAMI":{ "us-east-1":{ "AMIID":"ami-2b3b6041" }, "us-west-2":{ "AMIID":"ami-ac6872cd" }, "eu-west-1":{ "AMIID":"ami-03238b70" }, "ap-northeast-1":{ "AMIID":"ami-fb2f1295" }, "ap-southeast-2":{ "AMIID":"ami-43547120" }, "us-west-1":{ "AMIID":"ami-bfe095df" }, "ap-southeast-1":{ "AMIID":"ami-c78f43a4" }, "eu-central-1":{ "AMIID":"ami-e1e6f88d" } } }, "Resources":{ "MyVPC":{ "Type":"AWS::EC2::VPC", "Properties":{ "CidrBlock":{ "Fn::Join":[ "", [ { "Fn::FindInMap":[ "VPCIpSpace", { "Ref":"AWS::Region" }, "RANGE" ] }, ".", "0.0/16" ] ] }, "EnableDnsSupport":"true", "EnableDnsHostnames":"true", "Tags":[ { "Key":"Name", "Value":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-VPC" ] ] } } ] } }, "publicSubnet01":{ "Type":"AWS::EC2::Subnet", "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "CidrBlock":{ "Fn::Join":[ "", [ { "Fn::FindInMap":[ "VPCIpSpace", { "Ref":"AWS::Region" }, "RANGE" ] }, ".", { "Fn::FindInMap":[ "publicSubnetConfig", "publicSubnet01", "CIDR" ] } ] ] }, "AvailabilityZone":{ "Fn::Select":[ "2", { "Fn::GetAZs":{ "Ref":"AWS::Region" } } ] }, "Tags":[ { "Key":"SubnetType", "Value":"Public" }, { "Key":"Name", "Value":"publicSubnet01" } ] } }, "publicSubnet02":{ "Type":"AWS::EC2::Subnet", "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "MapPublicIpOnLaunch":"true", "CidrBlock":{ "Fn::Join":[ "", [ { "Fn::FindInMap":[ "VPCIpSpace", { "Ref":"AWS::Region" }, "RANGE" ] }, ".", { "Fn::FindInMap":[ "publicSubnetConfig", "publicSubnet02", "CIDR" ] } ] ] }, "AvailabilityZone":{ "Fn::Select":[ "3", { "Fn::GetAZs":{ "Ref":"AWS::Region" } } ] }, "Tags":[ { "Key":"SubnetType", "Value":"Public" }, { "Key":"Name", "Value":"publicSubnet02" } ] } }, "InternetGateway":{ "Type":"AWS::EC2::InternetGateway", "Properties":{ "Tags":[ { "Key":"Name", "Value":"DemoVPCIGW" } ] } }, "AttachGateway":{ "Type":"AWS::EC2::VPCGatewayAttachment", "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "InternetGatewayId":{ "Ref":"InternetGateway" } } }, "PublicRouteTable":{ "Type":"AWS::EC2::RouteTable", "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "Tags":[ { "Key":"Name", "Value":"PublicRouteTable" } ] } }, "PublicRoute":{ "Type":"AWS::EC2::Route", "Properties":{ "RouteTableId":{ "Ref":"PublicRouteTable" }, "DestinationCidrBlock":"0.0.0.0/0", "GatewayId":{ "Ref":"InternetGateway" } } }, "PublicSubnetRTAssociation01":{ "Type":"AWS::EC2::SubnetRouteTableAssociation", "Properties":{ "SubnetId":{ "Ref":"publicSubnet01" }, "RouteTableId":{ "Ref":"PublicRouteTable" } } }, "PublicSubnetRTAssociation02":{ "Type":"AWS::EC2::SubnetRouteTableAssociation", "Properties":{ "SubnetId":{ "Ref":"publicSubnet02" }, "RouteTableId":{ "Ref":"PublicRouteTable" } } }, "PublicNetworkAcl":{ "Type":"AWS::EC2::NetworkAcl", "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "Tags":[ { "Key":"Name", "Value":"NetworkAcl" } ] } }, "InboundPublicNAclEntry":{ "Type":"AWS::EC2::NetworkAclEntry", "Properties":{ "NetworkAclId":{ "Ref":"PublicNetworkAcl" }, "RuleNumber":"2000", "Protocol":"-1", "RuleAction":"allow", "Egress":"false", "CidrBlock":"0.0.0.0/0", "PortRange":{ "From":"0", "To":"65535" } } }, "OutboundPublicNetworkAclEntry":{ "Type":"AWS::EC2::NetworkAclEntry", "Properties":{ "NetworkAclId":{ "Ref":"PublicNetworkAcl" }, "RuleNumber":"2000", "Protocol":"-1", "RuleAction":"allow", "Egress":"true", "CidrBlock":"0.0.0.0/0", "PortRange":{ "From":"0", "To":"65535" } } }, "publicSubnetNetworkAclAssociation01":{ "Type":"AWS::EC2::SubnetNetworkAclAssociation", "Properties":{ "SubnetId":{ "Ref":"publicSubnet01" }, "NetworkAclId":{ "Ref":"PublicNetworkAcl" } } }, "publicSubnetNetworkAclAssociation02":{ "Type":"AWS::EC2::SubnetNetworkAclAssociation", "Properties":{ "SubnetId":{ "Ref":"publicSubnet02" }, "NetworkAclId":{ "Ref":"PublicNetworkAcl" } } }, "SourceSG":{ "Type":"AWS::EC2::SecurityGroup", "DependsOn":[ "MyVPC" ], "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "GroupDescription":"Sample source security group", "SecurityGroupIngress":[ { "IpProtocol":"tcp", "FromPort":"80", "ToPort":"80", "CidrIp":"0.0.0.0/0" } ], "Tags":[ { "Key":"Name", "Value":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-SourceSG" ] ] } } ] } }, "TargetSG":{ "Type":"AWS::EC2::SecurityGroup", "DependsOn":[ "MyVPC" ], "Properties":{ "VpcId":{ "Ref":"MyVPC" }, "GroupDescription":"ALL Inbound TCP - Source Restricted to SourceSG", "SecurityGroupIngress":[ { "IpProtocol":"tcp", "FromPort":"80", "ToPort":"80", "CidrIp":"0.0.0.0/0" } ], "Tags":[ { "Key":"Name", "Value":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-TargetSG" ] ] } } ] } }, "OutboundRule":{ "Type":"AWS::EC2::SecurityGroupEgress", "DependsOn":[ "MyVPC" ], "Properties":{ "IpProtocol":"tcp", "FromPort":"0", "ToPort":"65535", "DestinationSecurityGroupId":{ "Fn::GetAtt":[ "TargetSG", "GroupId" ] }, "GroupId":{ "Fn::GetAtt":[ "SourceSG", "GroupId" ] } } }, "InboundRule":{ "Type":"AWS::EC2::SecurityGroupIngress", "DependsOn":[ "MyVPC" ], "Properties":{ "IpProtocol":"tcp", "FromPort":"0", "ToPort":"65535", "SourceSecurityGroupId":{ "Fn::GetAtt":[ "TargetSG", "GroupId" ] }, "GroupId":{ "Fn::GetAtt":[ "TargetSG", "GroupId" ] } } }, "EcsCluster":{ "Type":"AWS::ECS::Cluster", "DependsOn":[ "MyVPC" ] }, "PhpTaskDefinition":{ "Type":"AWS::ECS::TaskDefinition", "DependsOn":[ "MyVPC" ], "Properties":{ "ContainerDefinitions":[ { "Name":"php-simple-app", "Cpu":"10", "Essential":"true", "Image":{ "Fn::Join":[ "", [ { "Ref":"AWS::AccountId" }, ".dkr.ecr.us-east-1.amazonaws.com/", { "Ref":"ECSRepoName" }, ":", { "Ref":"ImageTag" } ] ] }, "Memory":"300", "PortMappings":[ { "HostPort":80, "ContainerPort":80 } ] } ], "Volumes":[ { "Name":"my-vol" } ] } }, "EcsElb":{ "Type":"AWS::ElasticLoadBalancing::LoadBalancer", "DependsOn":[ "MyVPC" ], "Properties":{ "Subnets":[ { "Ref":"publicSubnet01" }, { "Ref":"publicSubnet02" } ], "Listeners":[ { "LoadBalancerPort":"80", "InstancePort":"80", "Protocol":"HTTP" } ], "SecurityGroups":[ { "Ref":"SourceSG" }, { "Ref":"TargetSG" } ], "HealthCheck":{ "Target":"HTTP:80/", "HealthyThreshold":"2", "UnhealthyThreshold":"10", "Interval":"30", "Timeout":"5" } } }, "ECSAutoScalingGroup":{ "Type":"AWS::AutoScaling::AutoScalingGroup", "DependsOn":[ "MyVPC" ], "Properties":{ "VPCZoneIdentifier":[ { "Ref":"publicSubnet01" }, { "Ref":"publicSubnet02" } ], "LaunchConfigurationName":{ "Ref":"ContainerInstances" }, "MinSize":"1", "MaxSize":{ "Ref":"MaxSize" }, "DesiredCapacity":{ "Ref":"DesiredCapacity" } }, "CreationPolicy":{ "ResourceSignal":{ "Timeout":"PT15M" } }, "UpdatePolicy":{ "AutoScalingRollingUpdate":{ "MinInstancesInService":"1", "MaxBatchSize":"1", "PauseTime":"PT15M", "WaitOnResourceSignals":"true" } } }, "ContainerInstances":{ "Type":"AWS::AutoScaling::LaunchConfiguration", "DependsOn":[ "MyVPC" ], "Metadata":{ "AWS::CloudFormation::Init":{ "config":{ "commands":{ "01_add_instance_to_cluster":{ "command":{ "Fn::Join":[ "", [ "#!/bin/bash\n", "echo ECS_CLUSTER=", { "Ref":"EcsCluster" }, " >> /etc/ecs/ecs.config" ] ] } } }, "files":{ "/etc/cfn/cfn-hup.conf":{ "content":{ "Fn::Join":[ "", [ "[main]\n", "stack=", { "Ref":"AWS::StackId" }, "\n", "region=", { "Ref":"AWS::Region" }, "\n" ] ] }, "mode":"000400", "owner":"root", "group":"root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf":{ "content":{ "Fn::Join":[ "", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.ContainerInstances.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref":"AWS::StackName" }, " --resource ContainerInstances ", " --region ", { "Ref":"AWS::Region" }, "\n", "runas=root\n" ] ] } } }, "services":{ "sysvinit":{ "cfn-hup":{ "enabled":"true", "ensureRunning":"true", "files":[ "/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf" ] } } } } } }, "Properties":{ "ImageId":{ "Fn::FindInMap":[ "AWSRegionToAMI", { "Ref":"AWS::Region" }, "AMIID" ] }, "SecurityGroups":[ { "Ref":"SourceSG" }, { "Ref":"TargetSG" } ], "InstanceType":{ "Ref":"InstanceType" }, "IamInstanceProfile":{ "Ref":"EC2InstanceProfile" }, "KeyName":{ "Ref":"KeyName" }, "UserData":{ "Fn::Base64":{ "Fn::Join":[ "", [ "#!/bin/bash -xe\n", "yum install -y aws-cfn-bootstrap\n", "/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref":"AWS::StackName" }, " --resource ContainerInstances ", " --region ", { "Ref":"AWS::Region" }, "\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref":"AWS::StackName" }, " --resource ECSAutoScalingGroup ", " --region ", { "Ref":"AWS::Region" }, "\n" ] ] } } } }, "EcsService":{ "Type":"AWS::ECS::Service", "DependsOn":[ "MyVPC", "ECSAutoScalingGroup" ], "Properties":{ "Cluster":{ "Ref":"EcsCluster" }, "DesiredCount":"1", "DeploymentConfiguration":{ "MaximumPercent":100, "MinimumHealthyPercent":0 }, "LoadBalancers":[ { "ContainerName":"php-simple-app", "ContainerPort":"80", "LoadBalancerName":{ "Ref":"EcsElb" } } ], "Role":{ "Ref":"EcsServiceRole" }, "TaskDefinition":{ "Ref":"PhpTaskDefinition" } } }, "EcsServiceRole":{ "Type":"AWS::IAM::Role", "Properties":{ "AssumeRolePolicyDocument":{ "Statement":[ { "Effect":"Allow", "Principal":{ "Service":[ "ecs.amazonaws.com" ] }, "Action":[ "sts:AssumeRole" ] } ] }, "Path":"/", "Policies":[ { "PolicyName":"ecs-service", "PolicyDocument":{ "Statement":[ { "Effect":"Allow", "Action":[ "elasticloadbalancing:Describe*", "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress" ], "Resource":"*" } ] } } ] } }, "EC2Role":{ "Type":"AWS::IAM::Role", "DependsOn":[ "MyVPC" ], "Properties":{ "AssumeRolePolicyDocument":{ "Statement":[ { "Effect":"Allow", "Principal":{ "Service":[ "ec2.amazonaws.com" ] }, "Action":[ "sts:AssumeRole" ] } ] }, "Path":"/", "Policies":[ { "PolicyName":"ecs-service", "PolicyDocument":{ "Statement":[ { "Effect":"Allow", "Action":[ "ecs:CreateCluster", "ecs:RegisterContainerInstance", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Submit*", "ecr:*", "ecs:Poll" ], "Resource":"*" } ] } } ] } }, "EC2InstanceProfile":{ "Type":"AWS::IAM::InstanceProfile", "DependsOn":[ "MyVPC" ], "Properties":{ "Path":"/", "Roles":[ { "Ref":"EC2Role" } ] } }, "JenkinsRole":{ "Type":"AWS::IAM::Role", "Properties":{ "AssumeRolePolicyDocument":{ "Statement":[ { "Sid":"", "Effect":"Allow", "Principal":{ "Service":"ec2.amazonaws.com" }, "Action":"sts:AssumeRole" } ] }, "Path":"/" } }, "JenkinsRolePolicies":{ "Type":"AWS::IAM::Policy", "Properties":{ "PolicyName":"JenkinsRole", "PolicyDocument":{ "Statement":[ { "Action":[ "*" ], "Effect":"Allow", "Resource":"*" } ] }, "Roles":[ { "Ref":"JenkinsRole" } ] } }, "JenkinsInstanceProfile":{ "Type":"AWS::IAM::InstanceProfile", "Properties":{ "Path":"/", "Roles":[ { "Ref":"JenkinsRole" } ] } }, "JenkinsSG":{ "Type":"AWS::EC2::SecurityGroup", "Properties":{ "GroupDescription":"Enable HTTP access on port 80", "VpcId":{ "Ref":"MyVPC" }, "SecurityGroupIngress":[ { "IpProtocol":"tcp", "FromPort":"22", "ToPort":"22", "CidrIp":{ "Ref":"YourIP" } }, { "IpProtocol":"tcp", "FromPort":"80", "ToPort":"80", "CidrIp":{ "Ref":"YourIP" } } ], "SecurityGroupEgress":[ { "IpProtocol":"tcp", "FromPort":"80", "ToPort":"80", "CidrIp":"0.0.0.0/0" }, { "IpProtocol":"tcp", "FromPort":"443", "ToPort":"443", "CidrIp":"0.0.0.0/0" }, { "IpProtocol":"udp", "FromPort":"123", "ToPort":"123", "CidrIp":"0.0.0.0/0" }, { "IpProtocol":"udp", "FromPort":"9418", "ToPort":"9418", "CidrIp":"0.0.0.0/0" }, { "IpProtocol":"icmp", "FromPort":"-1", "ToPort":"-1", "CidrIp":"0.0.0.0/0" } ], "Tags":[ { "Key":"Name", "Value":"JenkinsSG" } ] } }, "JenkinsServer":{ "Type":"AWS::EC2::Instance", "DependsOn":[ "EcsService", "JenkinsSG", "JenkinsRole", "ECSAutoScalingGroup" ], "Metadata":{ "AWS::CloudFormation::Init":{ "config":{ "packages":{ "yum":{ "java-1.7.0-openjdk":[ ], "java-1.7.0-openjdk-devel":[ ] } }, "files":{ "/tmp/config.xml":{ "source":"https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/config.xml", "mode":"644" }, "/tmp/hudson.tasks.Maven.xml":{ "source":"https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/hudson.tasks.Maven.xml", "mode":"644" }, "/tmp/jenkins.mvn.GlobalMavenConfig.xml":{ "source":"https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/jenkins.mvn.GlobalMavenConfig.xml", "mode":"644" } } } } }, "Properties":{ "KeyName":{ "Ref":"KeyName" }, "ImageId":{ "Fn::FindInMap":[ "AWSRegionVirt2AMI", { "Ref":"AWS::Region" }, { "Fn::FindInMap":[ "AWSInstanceType2Virt", "t2.large", "Virt" ] } ] }, "NetworkInterfaces":[ { "SubnetId":{ "Ref":"publicSubnet01" }, "GroupSet":[ { "Ref":"JenkinsSG" } ], "AssociatePublicIpAddress":"true", "DeviceIndex":"0" } ], "EbsOptimized":{ "Fn::FindInMap":[ "AWSInstanceType2EBSOpt", "t2.large", "EBSOpt" ] }, "InstanceType":"t2.large", "IamInstanceProfile":{ "Ref":"JenkinsInstanceProfile" }, "UserData":{ "Fn::Base64":{ "Fn::Join":[ "", [ "#!/bin/bash -ex\n", "yum update -y aws-cfn-bootstrap\n", "# Update the AWS CLI to the latest version\n", "yum install -y aws-cli\n", "function error_exit\n", "{\n", " /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", { "Ref":"JenkinsHostWaitHandle" }, "'\n", " exit 1\n", "}\n", "/opt/aws/bin/cfn-init -v -s ", { "Ref":"AWS::StackName" }, " -r JenkinsServer --region ", { "Ref":"AWS::Region" }, "\n", "# Install Docker\n", "cd /tmp/\n", "yum install -y docker\n", "service docker start\n", "chkconfig docker on\n", "# Wait 30 seconds to allow Docker to startup\n", "echo \"Waiting 30 seconds for Docker to start.....\"\n", "sleep 30\n", "yum -y install git*\n", "# Install Maven\n", "cd /tmp/\n", "wget http://mirror.cogentco.com/pub/apache/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz\n", "tar xzvf apache-maven-3.3.3-bin.tar.gz -C /opt/\n", "rm /tmp/apache-maven-3.3.3-bin.tar.gz\n", "# Install Jenkins\n", "wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo\n", "rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key\n", "yum install -y jenkins-1.658-1.1\n", "service jenkins start\n", "chkconfig jenkins on\n", "# Wait 30 seconds to allow Jenkins to startup\n", "echo \"Waiting 30 seconds for Jenkins to start.....\"\n", "sleep 30\n", "usermod -a -G docker jenkins\n", "# Install the required plugins\n", "cd /var/lib/jenkins/plugins\n", "curl -O -L https://updates.jenkins-ci.org/latest/aws-codepipeline.hpi\n", "chown jenkins:jenkins *.hpi\n", "mv /tmp/hudson.tasks.Maven.xml /var/lib/jenkins/\n", "mv /tmp/jenkins.mvn.GlobalMavenConfig.xml /var/lib/jenkins/\n", "chown jenkins:jenkins /var/lib/jenkins/*.xml\n", "# Restarting Jenkins\n", "service jenkins restart\n", "echo \"Waiting 30 seconds for Jenkins to start.....\"\n", "sleep 30\n", "# configure our job\n", "wget -P /tmp https://s3.amazonaws.com/stelligent-training-public/public/jenkins/config-template.xml\n", "/bin/sed -i \"s/APPNAME/", { "Ref":"AWS::StackName" }, "/g\" /tmp/config-template.xml\n", "/bin/sed -i \"s/MY_STACK/", { "Ref":"AWS::StackName" }, "/g\" /tmp/config-template.xml\n", "/bin/sed -i \"s/MY_ACCTID/", { "Ref":"AWS::AccountId" }, "/g\" /tmp/config-template.xml\n", "/bin/sed -i \"s/MY_ECR/", { "Ref":"ECSRepoName" }, "/g\" /tmp/config-template.xml\n", "/bin/sed -i \"s/REGION/", { "Ref":"AWS::Region" }, "/g\" /tmp/config-template.xml\n", "/usr/bin/java -jar /var/cache/jenkins/war/WEB-INF/jenkins-cli.jar -s http://localhost:8080 create-job ", { "Ref":"AWS::StackName" }, "< /tmp/config-template.xml\n", "# Set up port forwarding\n", "iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080\n", "iptables-save > /etc/sysconfig/iptables\n", "# If all went well, signal success\n", "/opt/aws/bin/cfn-signal -e $? -r 'Instance configuration complete' '", { "Ref":"JenkinsHostWaitHandle" }, "'\n", "\n" ] ] } }, "Tags":[ { "Key":"Name", "Value":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-Jenkins" ] ] } } ] } }, "JenkinsHostWaitHandle":{ "Type":"AWS::CloudFormation::WaitConditionHandle" }, "JenkinsHostWaitCondition":{ "Type":"AWS::CloudFormation::WaitCondition", "DependsOn":"JenkinsServer", "Properties":{ "Handle":{ "Ref":"JenkinsHostWaitHandle" }, "Timeout":"600" } }, "CodePipelineTrustRole":{ "Type":"AWS::IAM::Role", "Properties":{ "AssumeRolePolicyDocument":{ "Statement":[ { "Sid":"1", "Effect":"Allow", "Principal":{ "Service":[ "codepipeline.amazonaws.com" ] }, "Action":"sts:AssumeRole" } ] }, "Path":"/" } }, "CodePipelineRolePolicies":{ "Type":"AWS::IAM::Policy", "Properties":{ "PolicyName":"CodePipelinePolicy", "PolicyDocument":{ "Statement":[ { "Action":[ "s3:*" ], "Resource":[ "*" ], "Effect":"Allow" }, { "Action":[ "s3:PutBucketPolicy", "s3:PutObject" ], "Resource":[ { "Fn::Join":[ "", [ "arn:aws:s3:::demo-", { "Ref":"AWS::Region" }, "-", { "Ref":"AWS::AccountId" }, "-", { "Ref":"AWS::StackName" } ] ] } ], "Effect":"Allow" }, { "Action":[ "codecommit:GetBranch", "codecommit:GetCommit", "codecommit:UploadArchive", "codecommit:GetUploadArchiveStatus", "codecommit:CancelUploadArchive" ], "Resource":"*", "Effect":"Allow" }, { "Action":[ "codepipeline:*", "iam:ListRoles", "iam:PassRole", "codedeploy:CreateDeployment", "codedeploy:GetApplicationRevision", "codedeploy:GetDeployment", "codedeploy:GetDeploymentConfig", "codedeploy:RegisterApplicationRevision", "elasticbeanstalk:DescribeApplications", "elasticbeanstalk:DescribeEnvironments", "lambda:GetFunctionConfiguration", "lambda:ListFunctions" ], "Resource":"*", "Effect":"Allow" } ] }, "Roles":[ { "Ref":"CodePipelineTrustRole" } ] } }, "CustomJenkinsActionType":{ "Type":"AWS::CodePipeline::CustomActionType", "DependsOn":"JenkinsHostWaitCondition", "Properties":{ "Category":"Build", "Provider":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-Jenkins" ] ] }, "Version":"1", "ConfigurationProperties":[ { "Key":"true", "Name":"ProjectName", "Queryable":"true", "Required":"true", "Secret":"false", "Type":"String" } ], "InputArtifactDetails":{ "MaximumCount":5, "MinimumCount":0 }, "OutputArtifactDetails":{ "MaximumCount":5, "MinimumCount":0 }, "Settings":{ "EntityUrlTemplate":{ "Fn::Join":[ "", [ "http://", { "Fn::GetAtt":[ "JenkinsServer", "PublicIp" ] }, "/job/{Config:ProjectName}" ] ] }, "ExecutionUrlTemplate":{ "Fn::Join":[ "", [ "http://", { "Fn::GetAtt":[ "JenkinsServer", "PublicIp" ] }, "/job/{Config:ProjectName}/{ExternalExecutionId}" ] ] } } } }, "MyPipeline":{ "Type":"AWS::CodePipeline::Pipeline", "DependsOn":[ "CustomJenkinsActionType", "ECSAutoScalingGroup" ], "Properties":{ "Name":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-Pipeline" ] ] }, "RoleArn":{ "Fn::GetAtt":[ "CodePipelineTrustRole", "Arn" ] }, "Stages":[ { "Name":"Source", "Actions":[ { "InputArtifacts":[ ], "Name":"Source", "ActionTypeId":{ "Category":"Source", "Owner":"AWS", "Version":"1", "Provider":"CodeCommit" }, "OutputArtifacts":[ { "Name":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-SourceArtifact" ] ] } } ], "Configuration":{ "BranchName":{ "Ref":"RepositoryBranch" }, "RepositoryName":{ "Ref":"RepositoryName" } }, "RunOrder":1 } ] }, { "Name":"Build", "Actions":[ { "Name":"PmdBuild", "InputArtifacts":[ { "Name":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-SourceArtifact" ] ] } } ], "ActionTypeId":{ "Category":"Build", "Owner":"Custom", "Version":"1", "Provider":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-Jenkins" ] ] } }, "OutputArtifacts":[ { "Name":{ "Fn::Join":[ "", [ { "Ref":"AWS::StackName" }, "-BuiltArtifact" ] ] } } ], "Configuration":{ "ProjectName":{ "Ref":"AWS::StackName" } }, "RunOrder":1 } ] } ], "ArtifactStore":{ "Type":"S3", "Location":{ "Fn::Join":[ "", [ "codepipeline-", { "Ref":"AWS::Region" }, "-", { "Ref":"AWS::AccountId" } ] ] } } } } }, "Outputs":{ "AppURL":{ "Value":{ "Fn::Join":[ "", [ "http://", { "Fn::GetAtt":[ "EcsElb", "DNSName" ] }, "/" ] ] }, "Description":"URL to the working application running on ECS" }, "PipelineUrl":{ "Value":{ "Fn::Join":[ "", [ "https://console.aws.amazon.com/codepipeline/home?region=", { "Ref":"AWS::Region" }, "#/view/", { "Ref":"MyPipeline" } ] ] }, "Description":"Pipeline Url" }, "VpcId":{ "Value":{ "Ref":"MyVPC" }, "Description":"VPC ID of newly created VPC" }, "IGWId":{ "Value":{ "Ref":"InternetGateway" }, "Description":"Internet Gateway ID" }, "PublicSubnetA":{ "Value":{ "Ref":"publicSubnet01" }, "Description":"Public Subnet in AZ A" }, "JenkinsInstanceID":{ "Value":{ "Ref":"JenkinsServer" }, "Description":"Jenkins Instance ID" }, "JenkinsPublicIP":{ "Value":{ "Fn::GetAtt":[ "JenkinsServer", "PublicIp" ] }, "Description":"Jenkins Public IP Address" } } }