Overview

I use Ansible to create my various AWS VPC environments, including everything from the VPC itself, to subnets, security groups, EC2 instances and DNS records.

As I found the documentation for creating and managing Route53 private zones wanting, I would like to share how I have accomplished that as part of my Ansible playbooks.

In this tutorial, I am using the domain production.gnulnx.net along with the subnet 10.9.0.0/16

Follow along to see how you can use Ansible, along with Amazon Route53 service, to manage dynamic forward and reverse zones, allowing you to resolve hostnames to IP addresses, as well as IP addresses back to hostnames.

$ host core01
core01.production.gnulnx.net has address 10.9.2.60
$ host 10.9.2.60
60.2.9.10.in-addr.arpa domain name pointer core01.production.gnulnx.net.

Route53

You will want to create two zones - one for the forward, and one for the reverse.

For both hosted zones, you will want to set the Type to Private hosted zone for Amazon VPC, as well as select the appropriate VPC from the VPC ID dropdown

When creating the forward and reverse zones, I use these values, respectively:

Forward Domain Name: production.gnulnx.net
Reverse Domain Name: 9.10.in-addr.arpa

VPC

You will want to create a DHCP Options Set for this VPC.

domain-name = production.gnulnx.net
domain-name-servers = AmazonProvidedDNS

And then assign the DHCP options set to the VPC by navigating to Your VPCs and then selecting Edit DHCP Options Set.

In addition, ensure that DNS Resolution and DNS Hostnames are both set to yes

Ansible

This is my main prod file, which includes all of the individual pieces. The important bits are ec2.yml and route53.yml, so I will show those below.

$ cat environments/prod/main.yml 
---

- name: Create the Production AWS VPC environment
  hosts: localhost
  connection: local
  gather_facts: no
  vars:
    aws_region: us-east-1
  tasks:
    - include: vpc.yml
    - include: securitygroups.yml
    - include: nat.yml
    - include: elb.yml
    - include: subnetgroups.yml
    - include: rds.yml
    - include: ec2.yml
    - include: eip.yml
    - include: route53.yml

Now for the ec2.yml file, where I create EC2 instances and then register them as ansible variables.

$ cat environments/prod/ec2.yml
---

- name: Create Production core01 EC2 instance
  ec2:
    key_name: kyle
    instance_type: m4.xlarge
    region: "{{ aws_region }}"
    image: ami-9a562df2
    group_id: ["{{ coresg.group_id }}", "{{ sshablesg.group_id }}"]
    wait: yes
    vpc_subnet_id: "{{ vpc.subnets[2].id }}"
    assign_public_ip: no
    source_dest_check: true
    instance_profile_name: coreprod
    instance_tags:
      Name: core01
      Environment: production
      Role: core
    exact_count: 1
    count_tag:
      Name: core01
      Environment: production
      Role: core
  register: core01

- name: Create Production core02 EC2 instance
  ec2:
    key_name: kyle
    instance_type: m4.xlarge
    region: "{{ aws_region }}"
    image: ami-9a562df2
    group_id: ["{{ coresg.group_id }}", "{{ sshablesg.group_id }}"]
    wait: yes
    vpc_subnet_id: "{{ vpc.subnets[3].id }}"
    assign_public_ip: no
    source_dest_check: true
    instance_profile_name: coreprod
    instance_tags:
      Name: core02
      Environment: production
      Role: core
    exact_count: 1
    count_tag:
      Name: core02
      Environment: production
      Role: core
  register: core02

Finally, I create forward and reverse records for the registered variables.

$ cat environments/prod/route53.yml
---

- name: Create Production EC2 Private Forward DNS records
  route53:
    command: create
    zone: production.gnulnx.net
    private_zone: yes
    overwrite: yes
    record: "{{ item.tagged_instances[0].tags['Name'] }}.production.gnulnx.net"
    type: A
    value: "{{ item.tagged_instances[0].private_ip }}"
  with_items:
    - "{{ core01 }}"
    - "{{ core02 }}"

- name: Create Production EC2 Private Reverse DNS records
  route53:
    command: create
    zone: 1.10.in-addr.arpa
    private_zone: yes
    overwrite: yes
    record: "{{ item.tagged_instances[0].private_ip | ipaddr('revdns') }}"
    type: PTR
    value: "{{ item.tagged_instances[0].tags['Name'] }}.production.gnulnx.net"
  with_items:
    - "{{ core01 }}"
    - "{{ core02 }}"