1. Home

Anil Lakhman

< Blog />

Domain stack template for AWS Cloudformation

in

This was a template I created with troposphere and launches a domain stack on AWS via cloudformation.

You specify the ZoneRecordName and select an existing HostedZoneId via the parameters, and we create a new domain type A record in Route53.

ZoneRecordName
The record name to be created e.g: anil.io, dev.domain.com
HostedZoneId
The hosted zone id from Route53 for this domain. e.g: Z5JQDH44CCPRO
ElasticIP (Export)
The elastic ip that was created and attached to ZoneRecordName
DomainName
String value of the ZoneRecordName

Note

  • I was testing this in the eu-west-2 (London) region, you may have to modify this to match your geographic region
  • To build this template use pip install troposphere and then run the file via python domain-stack.py
# -*- coding: utf-8 -*-
from __future__ import print_function
import os

from troposphere import Output, route53, Export
from troposphere import Parameter, Ref, Template
from troposphere.ec2 import EIP

#
# Troposphere template - https://github.com/cloudtools/troposphere
# Run `python domain-stack.py` to create a JSON file to upload to CF
#

#
# ┌───────────────────────────────────────────────────────────────────────────┐
# │                         Template & Parameters                             │
# └───────────────────────────────────────────────────────────────────────────┘
#
# - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
#
template = Template()
template.add_description("Domain stack | anil.io")


#
# To be provided by the User in the console
#
hosted_zone_id = template.add_parameter(Parameter(
    "HostedZoneId",
    Description="The ID of an existing Amazon Route 53 hosted zone. (e.g: Z5XPQH44DDPFO)",
    Type="AWS::Route53::HostedZone::Id",
))

hosted_zone_record_domain = template.add_parameter(Parameter(
    "ZoneRecordName",
    Description="The domain name record that will be created. (e.g: www.lakhman.com, dev.lakhman.com)",
    Type="String",
))

#
# ┌───────────────────────────────────────────────────────────────────────────┐
# │                               Elastic IP                                  │
# └───────────────────────────────────────────────────────────────────────────┘
#
elastic_ip = template.add_resource(
    EIP('ElasticIP',
        Domain='vpc',

        # Always retain elastic IP's (on CF delete)
        # DeletionPolicy='Retain'

        # Optional: We'll use this later when we set our VPC
        # DependsOn='AttachGateway',

        # Optional: Attach elastic ip to an instance
        # InstanceId=Ref(ec2_linux_instance), # Optional
        )
)
template.add_output(Output("ElasticIP", Value=Ref(elastic_ip), Export=Export(name="ElasticIP")))


#
# ┌───────────────────────────────────────────────────────────────────────────┐
# │                             Route 53 (DNS)                                │
# └───────────────────────────────────────────────────────────────────────────┘
#
# - Create a route 53 record set
# - Attach our Elastic IP to our DNS name
#
DNSRecord = template.add_resource(route53.RecordSetType(
    "DNS",
    HostedZoneId=Ref(hosted_zone_id),
    Name=Ref(hosted_zone_record_domain),
    Type="A",
    TTL="400",
    ResourceRecords=[Ref(elastic_ip)],
    # Always retain IP on cloud formation delete
    # DeletionPolicy='Retain'
))

template.add_output(Output("DomainName", Value=Ref(DNSRecord)))

#
# ┌───────────────────────────────────────────────────────────────────────────┐
# │                                 JSON DUMP                                 │
# └───────────────────────────────────────────────────────────────────────────┘
#
with open(os.path.realpath(__file__)[:-2] + 'json', 'w') as the_file:
    print(template.to_json(), file=the_file)
    print('Generated: ' + __file__)
{
    "Description": "Domain stack | anil.io",
    "Metadata": {
        "AWS::CloudFormation::Interface": {
            "ParameterGroups": [
                {
                    "Label": {
                        "default": "Domain Configuration"
                    },
                    "Parameters": [
                        "HostedZoneId",
                        "ZoneRecordName"
                    ]
                }
            ],
            "ParameterLabels": {
                "HostedZoneId": {
                    "default": "Hosted Zone ID"
                },
                "ZoneRecordName": {
                    "default": "DNS record name"
                }
            }
        }
    },
    "Outputs": {
        "DomainName": {
            "Value": {
                "Ref": "DNS"
            }
        },
        "ElasticIP": {
            "Export": {
                "Name": "ElasticIP"
            },
            "Value": {
                "Ref": "ElasticIP"
            }
        }
    },
    "Parameters": {
        "HostedZoneId": {
            "Description": "The ID of an existing Amazon Route 53 hosted zone. (e.g: Z5XPQH44DDPFO)",
            "Type": "AWS::Route53::HostedZone::Id"
        },
        "ZoneRecordName": {
            "Description": "The domain name record that will be created. (e.g: www.lakhman.com, dev.lakhman.com)",
            "Type": "String"
        }
    },
    "Resources": {
        "DNS": {
            "Properties": {
                "HostedZoneId": {
                    "Ref": "HostedZoneId"
                },
                "Name": {
                    "Ref": "ZoneRecordName"
                },
                "ResourceRecords": [
                    {
                        "Ref": "ElasticIP"
                    }
                ],
                "TTL": "400",
                "Type": "A"
            },
            "Type": "AWS::Route53::RecordSet"
        },
        "ElasticIP": {
            "Properties": {
                "Domain": "vpc"
            },
            "Type": "AWS::EC2::EIP"
        }
    }
}