Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1638 lines (1636 sloc) 53.5 KB
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "AWS CloudFormation template to create an IAM role, Security Groups, Consul Server and cluster of Consul agents in an ECS Cluster. Please note that this is not designed for production usage.",
"Mappings": {
"ConsulServerAmiMap": {
"eu-west-1": {
"AMI": "ami-a10897d6"
},
"us-east-1": {
"AMI": "ami-1ecae776"
},
"us-west-2": {
"AMI": "ami-e7527ed7"
}
},
"EcsNodeAmiMap": {
"eu-west-1": {
"AMI": "ami-bdafdbdd"
},
"us-east-1": {
"AMI": "ami-cb2305a1"
},
"us-west-2": {
"AMI": "ami-ec75908c"
}
},
"DcMap": {
"eu-west-1": {
"Value": "eu1"
},
"us-east-1": {
"Value": "us1"
},
"us-west-2": {
"Value": "us2"
}
}
},
"Parameters": {
"VpcCidr": {
"Type": "String",
"Description": "Optional - CIDR/IP range for vpc - defaults to 10.20.0.0/16",
"Default": "10.20.0.0/16"
},
"SubnetCidr1": {
"Type": "String",
"Description": "Optional - CIDR/IP range for subnet - defaults to 10.20.0.0/24",
"Default": "10.20.0.0/24"
},
"SubnetCidr2": {
"Type": "String",
"Description": "Optional - CIDR/IP range for subnet - defaults to 10.20.0.0/24",
"Default": "10.20.1.0/24"
},
"AZ1": {
"Type": "AWS::EC2::AvailabilityZone::Name",
"Description": "The Availability Zone of subnet 1."
},
"AZ2": {
"Type": "AWS::EC2::AvailabilityZone::Name",
"Description": "The Availability Zone of subnet 2. Must be different than AZ1."
},
"EcsInstanceType": {
"Type": "String",
"Description": "ECS instance type",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"t2.small",
"t2.medium",
"m3.medium",
"m3.large",
"m3.xlarge",
"m3.2xlarge",
"c4.large",
"c4.xlarge",
"c4.2xlarge",
"c4.4xlarge",
"c4.8xlarge",
"c3.large",
"c3.xlarge",
"c3.2xlarge",
"c3.4xlarge",
"c3.8xlarge",
"r3.large",
"r3.xlarge",
"r3.2xlarge",
"r3.4xlarge",
"r3.8xlarge",
"i2.xlarge",
"i2.2xlarge",
"i2.4xlarge",
"i2.8xlarge"
],
"ConstraintDescription": "must be a valid EC2 instance type."
},
"ServerInstanceType": {
"Type": "String",
"Description": "Consul Server EC2 instance type",
"Default": "t2.micro",
"AllowedValues": [
"t2.micro",
"t2.small",
"t2.medium",
"m3.medium",
"m3.large",
"m3.xlarge",
"m3.2xlarge",
"c4.large",
"c4.xlarge",
"c4.2xlarge",
"c4.4xlarge",
"c4.8xlarge",
"c3.large",
"c3.xlarge",
"c3.2xlarge",
"c3.4xlarge",
"c3.8xlarge",
"r3.large",
"r3.xlarge",
"r3.2xlarge",
"r3.4xlarge",
"r3.8xlarge",
"i2.xlarge",
"i2.2xlarge",
"i2.4xlarge",
"i2.8xlarge"
],
"ConstraintDescription": "must be a valid EC2 instance type."
},
"KeyName": {
"Type": "AWS::EC2::KeyPair::KeyName",
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the EC2 instances"
},
"ClusterSize": {
"Type": "Number",
"Description": "Expected size of the ECS cluster",
"Default": "3"
},
"SourceCidr": {
"Type": "String",
"Description": "Optional - CIDR/IP range for ECS instance outside access - defaults to 0.0.0.0/0",
"Default": "0.0.0.0/0"
},
"AmazonDnsIp": {
"Type": "String",
"Description": "The IP address of the VPC DNS service running on a reserved IP address at the base of the VPC network range \"plus two\". ",
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})",
"Default": "10.20.0.2"
},
"HttpPassword": {
"Type": "String",
"NoEcho": "true",
"Description": "The HTTP password for access to the Consul GUI",
"Default": "password"
},
"DBName": {
"Type": "String",
"Description": "The name of the database.",
"Default": "postgres"
},
"DBUsername": {
"Type": "String",
"Description": "The username for access to the database.",
"Default": "postgres"
},
"DBPassword": {
"Type": "String",
"NoEcho": "true",
"Description": "The password for access to the database.",
"AllowedPattern": "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,20})",
"ConstraintDescription": "Entry that must contains one digit from 0-9, one lowercase characters, one uppercase characters and is between 6 and 20 characters in length.",
"Default": "Passw0rd"
}
},
"Resources": {
"IGW": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"gateway"
]
]
}
}
]
}
},
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": {
"Ref": "VpcCidr"
},
"EnableDnsSupport": true,
"EnableDnsHostnames": true,
"InstanceTenancy": "default",
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"vpc"
]
]
}
}
]
}
},
"RT": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"route-table"
]
]
}
}
]
}
},
"AttachGateway": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"InternetGatewayId": {
"Ref": "IGW"
}
}
},
"RTEX": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "RT"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "IGW"
}
},
"DependsOn": [
"AttachGateway"
]
},
"SUB1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": {
"Ref": "SubnetCidr1"
},
"AvailabilityZone": {
"Ref": "AZ1"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"subnet1"
]
]
}
}
]
}
},
"SUB2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": {
"Ref": "SubnetCidr2"
},
"AvailabilityZone": {
"Ref": "AZ2"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"subnet2"
]
]
}
}
]
}
},
"SUB1NACLJYF4": {
"Type": "AWS::EC2::SubnetNetworkAclAssociation",
"Properties": {
"NetworkAclId": {
"Fn::GetAtt" : ["VPC" , "DefaultNetworkAcl"]
},
"SubnetId": {
"Ref": "SUB1"
}
}
},
"SUB1RTE3CND": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"RouteTableId": {
"Ref": "RT"
},
"SubnetId": {
"Ref": "SUB1"
}
}
},
"ConsulAgentSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Consul Agent Security Group",
"VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"ConsulAgentSG"
]
]
}
}
]
}
},
"ConsulServerSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Consul Server Security Group",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "8300",
"ToPort": "8300",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"ConsulServerSG"
]
]
}
}
]
}
},
"ConsulAgentSecurityGroupIngressTcpEphemeral": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "32768",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressUdpEphemeral": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "udp",
"FromPort": "32768",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressDnsUdp": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "udp",
"FromPort": "8600",
"ToPort": "8600",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressDnsTcp": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "8600",
"ToPort": "8600",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressHttp": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "8500",
"ToPort": "8500",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressCli": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "8400",
"ToPort": "8400",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressSerfLanUdp": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "udp",
"FromPort": "8301",
"ToPort": "8301",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulAgentSecurityGroupIngressSerfLanTcp": {
"DependsOn": [
"ConsulAgentSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulAgentSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "8301",
"ToPort": "8301",
"SourceSecurityGroupId": {
"Ref": "ConsulAgentSecurityGroup"
}
}
},
"ConsulServerSecurityGroupIngressSerfWanTcp": {
"DependsOn": [
"ConsulServerSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulServerSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "8302",
"ToPort": "8302",
"SourceSecurityGroupId": {
"Ref": "ConsulServerSecurityGroup"
}
}
},
"ConsulServerSecurityGroupIngressSerfWanUdp": {
"DependsOn": [
"ConsulServerSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "ConsulServerSecurityGroup"
},
"IpProtocol": "udp",
"FromPort": "8302",
"ToPort": "8302",
"SourceSecurityGroupId": {
"Ref": "ConsulServerSecurityGroup"
}
}
},
"CommonSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "ECS Security Group",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "SourceCidr"
}
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
},
{
"IpProtocol": "tcp",
"FromPort": "443",
"ToPort": "443",
"CidrIp": "0.0.0.0/0"
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"CommonSG"
]
]
}
}
]
}
},
"EcsInstanceSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "ECS Instance Security Group",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": {
"Ref": "VpcCidr"
}
},
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": {
"Ref": "VpcCidr"
}
},
{
"IpProtocol": "tcp",
"FromPort": "8080",
"ToPort": "8080",
"CidrIp": {
"Ref": "VpcCidr"
}
},
{
"IpProtocol": "tcp",
"FromPort": "8080",
"ToPort": "8080",
"SourceSecurityGroupId": {
"Ref": "EcsLoadBalancerSecurityGroup"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"EcsInstanceSG"
]
]
}
}
]
}
},
"EcsInstanceSecurityGroupIngressTcpWellKnown": {
"DependsOn": [
"EcsInstanceSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "EcsInstanceSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "1",
"ToPort": "1023",
"SourceSecurityGroupId": {
"Ref": "EcsInstanceSecurityGroup"
}
}
},
"EcsInstanceSecurityGroupIngressTcpRegistered": {
"DependsOn": [
"EcsInstanceSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "EcsInstanceSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "1024",
"ToPort": "49151",
"SourceSecurityGroupId": {
"Ref": "EcsInstanceSecurityGroup"
}
}
},
"EcsInstanceSecurityGroupIngressTcpEphemeral": {
"DependsOn": [
"EcsInstanceSecurityGroup"
],
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "EcsInstanceSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": "49152",
"ToPort": "65535",
"SourceSecurityGroupId": {
"Ref": "EcsInstanceSecurityGroup"
}
}
},
"EcsLoadBalancerSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "ECS Load Balancer Security Group",
"VpcId": {
"Ref": "VPC"
},
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "80",
"ToPort": "80",
"CidrIp": "0.0.0.0/0"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "tcp",
"FromPort": "8080",
"ToPort": "8080",
"CidrIp": {
"Ref": "VpcCidr"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"EcsLBSG"
]
]
}
}
]
}
},
"ConsulRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecs:CreateCluster",
"ecs:DeregisterContainerInstance",
"ecs:DiscoverPollEndpoint",
"ecs:Poll",
"ecs:RegisterContainerInstance",
"ecs:Submit*",
"ecr:GetAuthorizationToken",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:*"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
}
}
]
}
},
"ConsulInstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [
{
"Ref": "ConsulRole"
}
]
}
},
"ConsulServer": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets": {
"InstallAndRun": [
"Install",
"Configure",
"StartContainers"
]
},
"Install": {
"packages": {
"yum": {
"awslogs": [],
"git": [],
"docker": [],
"nginx": [],
"httpd-devel": []
}
},
"files": {
"/etc/nginx/nginx.conf": {
"content": {
"Fn::Join": [
"\n",
[
"user nginx;",
"worker_processes 1;",
"error_log /var/log/nginx/error.log;",
"pid /var/run/nginx.pid;",
"events {",
" worker_connections 1024;",
"}",
"",
"http {",
" server {",
" listen 80;",
" location / {",
" proxy_set_header Host $host;",
" proxy_set_header X-Real-IP $remote_addr;",
" proxy_pass http://localhost:8500;",
" auth_basic \"Restricted\";",
" auth_basic_user_file /etc/nginx/.htpasswd;",
" }",
" }",
"}"
]
]
},
"mode": "000755",
"owner": "root",
"group": "root"
},
"/etc/postgres/register-postgres-service.sh": {
"content": {
"Fn::Join": [
"\n",
[
"#!/bin/env bash",
"curl -i --retry 10 --retry-delay 5 -H 'Content-Type: application/json' -X PUT --data \"@-\" http://localhost:8500/v1/catalog/register << EOF",
"{",
" \"Node\": \"$1\",",
" \"Address\": \"$(dig +short $1)\",",
" \"Service\": {",
" \"ID\": \"postgres1\",",
" \"Service\": \"postgres\",",
" \"Tags\": [",
" \"master\"",
" ],",
" \"Port\": $2",
" }",
"}",
"EOF"
]
]
},
"mode": "000755",
"owner": "root",
"group": "root"
}
},
"services": {
"sysvinit": {
"nginx": {
"enabled": "true",
"ensureRunning": "true",
"files": [
"/etc/nginx/nginx.conf"
]
},
"docker": {
"enabled": "true",
"ensureRunning": "true"
},
"awslogs": {
"enabled": "true",
"ensureRunning": "true"
}
}
}
},
"Configure": {
"commands": {
"01_create_consul_data_dir": {
"command": {
"Fn::Join": [
"",
[
"mkdir -p /opt/consul"
]
]
}
},
"02_add_user_to_docker_group": {
"command": {
"Fn::Join": [
"",
[
"usermod -a -G docker ec2-user"
]
]
}
},
"03_pull_consul_image": {
"command": {
"Fn::Join": [
"",
[
"docker pull progrium/consul"
]
]
}
},
"04_set_nginx_http_password": {
"command": {
"Fn::Join": [
" ",
[
"htpasswd -cb /etc/nginx/.htpasswd admin '",
{
"Ref": "HttpPassword"
},
"'"
]
]
}
},
"05_reload_nginx": {
"command": {
"Fn::Join": [
"",
[
"/usr/sbin/nginx -s reload"
]
]
}
}
}
},
"StartContainers": {
"commands": {
"01_start_consul_docker_container": {
"command": {
"Fn::Join": [
" ",
[
"docker run -d --restart=always -p 8300:8300 -p 8301:8301 -p 8301:8301/udp",
"-p 8302:8302 -p 8302:8302/udp -p 8400:8400 -p 8500:8500 -p 53:53/udp",
"-v /opt/consul:/data",
"-h $(curl -s http://169.254.169.254/latest/meta-data/instance-id)",
"--name consul-server progrium/consul -server -bootstrap",
"-dc",
{
"Fn::FindInMap": [
"DcMap",
{
"Ref": "AWS::Region"
},
"Value"
]
},
"-advertise $(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)",
"-ui-dir /ui"
]
]
}
},
"02_register_postgres_service_in_consul": {
"command": {
"Fn::Join": [
" ",
[
"/etc/postgres/register-postgres-service.sh",
{ "Fn::GetAtt": ["DBInstance", "Endpoint.Address"] },
{ "Fn::GetAtt": ["DBInstance", "Endpoint.Port"] }
]
]
}
}
}
}
}
},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"ConsulServerAmiMap",
{
"Ref": "AWS::Region"
},
"AMI"
]
},
"InstanceType": {
"Ref": "ServerInstanceType"
},
"IamInstanceProfile": {
"Ref": "ConsulInstanceProfile"
},
"KeyName": {
"Ref": "KeyName"
},
"NetworkInterfaces": [
{
"GroupSet": [
{
"Ref": "ConsulServerSecurityGroup"
},
{
"Ref": "ConsulAgentSecurityGroup"
},
{
"Ref": "CommonSecurityGroup"
}
],
"AssociatePublicIpAddress": "true",
"DeviceIndex": "0",
"DeleteOnTermination": "true",
"SubnetId": {
"Ref": "SUB1"
}
}
],
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"ConsulServer"
]
]
}
},
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
}
}
],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"yum update -y\n",
"yum update -y aws-cfn-bootstrap\n",
"# Install the files and packages from the metadata\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource ConsulServer ",
" --configsets InstallAndRun ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource ConsulServer ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Count": "1",
"Timeout": "PT15M"
}
},
"DependsOn": [
"DBInstance"
]
},
"EcsCluster": {
"Type" : "AWS::ECS::Cluster"
},
"EcsInstanceLc": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"DependsOn": "ConsulServer",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets": {
"InstallAndRun": [
"Install",
"Configure",
"StartContainers"
]
},
"Install": {
"packages": {
"yum": {
"awslogs": []
}
},
"files": {
"/etc/sysconfig/docker": {
"content": {
"Fn::Join": [
" ",
[
"OPTIONS='--dns 172.17.0.1 --dns",
{
"Ref": "AmazonDnsIp"
},
"--dns-search service.consul'"
]
]
},
"mode": "000755",
"owner": "root",
"group": "root"
},
"/etc/consul/consul.json": {
"content": {
"Fn::Join": [
"",
[
"{ \"leave_on_terminate\": true, \"recursors\": [ \"",
{
"Ref": "AmazonDnsIp"
},
"\"] }"
]
]
},
"mode": "000755",
"owner": "root",
"group": "root"
},
"/etc/ecs/ecs.config": {
"content": {
"Fn::Join": [
"",
[
"ECS_CLUSTER=",
{
"Ref": "EcsCluster"
}
]
]
},
"mode": "000755",
"owner": "root",
"group": "root"
}
},
"services": {
"sysvinit": {
"awslogs": {
"enabled": "true",
"ensureRunning": "true"
}
}
}
},
"Configure": {
"commands": {
"01_create_consul_data_dir": {
"command": {
"Fn::Join": [
"",
[
"mkdir -p /opt/consul"
]
]
}
},
"02_add_user_to_docker_group": {
"command": {
"Fn::Join": [
"",
[
"usermod -a -G docker ec2-user"
]
]
}
},
"03_restart_docker": {
"command": {
"Fn::Join": [
"",
[
"/sbin/service docker restart"
]
]
}
},
"04_pause_to_wait_for_docker_restart": {
"command": {
"Fn::Join": [
"",
[
"/bin/sleep 5"
]
]
}
},
"05_start_ecs_if_not_running": {
"command": {
"Fn::Join": [
"",
[
"[[ $(/sbin/status ecs) =~ \"running\" ]] || /sbin/start ecs"
]
]
}
},
"06_pull_consul_image": {
"command": {
"Fn::Join": [
"",
[
"docker pull progrium/consul"
]
]
}
},
"07_pull_registrator_image": {
"command": {
"Fn::Join": [
"",
[
"docker pull gliderlabs/registrator"
]
]
}
},
"08_start_awslogs_if_not_running": {
"command": {
"Fn::Join": [
"",
[
"[[ $(/sbin/status awslogs) =~ \"running\" ]] || /sbin/service awslogs start"
]
]
}
}
}
},
"StartContainers": {
"commands": {
"01_start_consul_docker_container": {
"command": {
"Fn::Join": [
" ",
[
"docker run -d --restart=always -p 8301:8301 -p 8301:8301/udp",
"-p 8400:8400 -p 8500:8500 -p 53:53/udp",
"-v /opt/consul:/data -v /var/run/docker.sock:/var/run/docker.sock",
"-v /etc/consul:/etc/consul",
"-h $(curl -s http://169.254.169.254/latest/meta-data/instance-id)",
"--name consul-agent progrium/consul -join",
{
"Fn::GetAtt": [
"ConsulServer",
"PrivateIp"
]
},
"-advertise $(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) -dc",
{
"Fn::FindInMap": [
"DcMap",
{
"Ref": "AWS::Region"
},
"Value"
]
},
"-config-file /etc/consul/consul.json"
]
]
}
},
"02_start_registrator_docker_container": {
"command": {
"Fn::Join": [
" ",
[
"docker run -d --restart=always -v /var/run/docker.sock:/tmp/docker.sock",
"-h $(curl -s http://169.254.169.254/latest/meta-data/instance-id)",
"--name consul-registrator gliderlabs/registrator:latest",
"-ip $(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)",
"consul://$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4):8500"
]
]
}
}
}
}
}
},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"EcsNodeAmiMap",
{
"Ref": "AWS::Region"
},
"AMI"
]
},
"InstanceType": {
"Ref": "EcsInstanceType"
},
"AssociatePublicIpAddress": true,
"IamInstanceProfile": {
"Ref": "ConsulInstanceProfile"
},
"SecurityGroups": [
{
"Ref": "ConsulAgentSecurityGroup"
},
{
"Ref": "CommonSecurityGroup"
},
{
"Ref": "EcsInstanceSecurityGroup"
}
],
"KeyName": {
"Ref": "KeyName"
},
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"yum update -y\n",
"yum install -y aws-cfn-bootstrap\n",
"# Install the files and packages from the metadata\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EcsInstanceLc ",
" --configsets InstallAndRun ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EcsInstanceAsg ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
}
}
},
"EcsLoadBalancer" : {
"Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties" : {
"Subnets" : [ { "Ref": "SUB1" }, { "Ref": "SUB2" } ],
"Listeners" : [ {
"LoadBalancerPort" : "80",
"InstancePort" : "8080",
"Protocol" : "HTTP"
} ],
"HealthCheck" : {
"Target" : "HTTP:8080/health",
"HealthyThreshold" : "3",
"UnhealthyThreshold" : "5",
"Interval" : "30",
"Timeout" : "5"
},
"SecurityGroups": [
{ "Ref": "EcsLoadBalancerSecurityGroup" }
]
},
"DependsOn": [
"AttachGateway"
]
},
"EcsInstanceAsg": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": [
{
"Ref": "AZ1"
}
],
"VPCZoneIdentifier": [
{
"Ref": "SUB1"
}
],
"LaunchConfigurationName": {
"Ref": "EcsInstanceLc"
},
"LoadBalancerNames": [
{
"Ref": "EcsLoadBalancer"
}
],
"MinSize": {
"Ref": "ClusterSize"
},
"MaxSize": {
"Ref": "ClusterSize"
},
"DesiredCapacity": {
"Ref": "ClusterSize"
},
"Tags": [
{
"Key": "Application",
"Value": {
"Ref": "AWS::StackName"
},
"PropagateAtLaunch": "true"
},
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"ECS Instance"
]
]
},
"PropagateAtLaunch": "true"
}
]
}
},
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties" : {
"GroupDescription": "Open database for access from services",
"EC2VpcId": {
"Ref": "VPC"
},
"Tags": [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"DBSG"
]
]
}
}
],
"DBSecurityGroupIngress" : [{
"EC2SecurityGroupId" : { "Ref" : "ConsulAgentSecurityGroup" }
}]
}
},
"DBSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"DBSubnetGroupDescription" : "The subnet group for postgres db.",
"SubnetIds" : [ { "Ref": "SUB1"}, { "Ref": "SUB2" } ],
"Tags" : [
{
"Key": "Name",
"Value": {
"Fn::Join": [
"-",
[
{ "Ref": "AWS::StackName" },
"DBSubnetGroup"
]
]
}
}
]
}
},
"DBInstance": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"AvailabilityZone" : { "Ref" : "AZ1" },
"DBName" : { "Ref": "DBName" },
"Engine" : "postgres",
"MultiAZ" : false,
"MasterUsername" : { "Ref": "DBUsername" },
"DBInstanceClass" : "db.t2.micro",
"AllocatedStorage" : 5,
"MasterUserPassword": { "Ref": "DBPassword" },
"DBSecurityGroups" : [ { "Ref": "DBSecurityGroup" } ],
"DBSubnetGroupName" : { "Ref": "DBSubnetGroup" }
}
}
},
"Outputs": {
"ConsulServerURL": {
"Description": "Name of the ConsulServer instance",
"Value": {
"Fn::Join": [
"",
[
"http://",
{
"Fn::GetAtt": [
"ConsulServer",
"PublicDnsName"
]
},
"/ui"
]
]
}
},
"SshCommand": {
"Description": "SSH command to access the ConsulServer instance",
"Value": {
"Fn::Join": [
"",
[
"ssh ec2-user@",
{
"Fn::GetAtt": [
"ConsulServer",
"PublicDnsName"
]
}
]
]
}
},
"EcsLoadBalancerUrl": {
"Description": "URL of load balancer.",
"Value": {
"Fn::GetAtt": [ "EcsLoadBalancer", "DNSName" ]
}
},
"EcsInstanceAsgName": {
"Description": "Auto Scaling Group Name for ECS Instances",
"Value": {
"Ref": "EcsInstanceAsg"
}
},
"EcsClusterName": {
"Description": "ECS Cluster Name",
"Value": {
"Ref": "EcsCluster"
}
}
}
}