Manage AWS Route53 with Ansible

Page content

I need to automate AWS Route 53 operation with Ansible, and here is a note. (As Ansible always does, most useful informations are in the official document.)

Set up environment

Install boto

According to the Ansible official document, We need to install boto (AWS SDK for Python).

pip install -U boto

Get AWS API keys and export it

boto uses two keys in order to use AWS API under the hood. Here is a good guide how to get the keys. After obtaining the keys, we should export your Ansible execution environment.

There are several methods in an official document, and I use For environment variables method.

export AWS_ACCESS_KEY_ID='AK123'
export AWS_SECRET_ACCESS_KEY='abc123'

How to use AWS Route53 module in Ansible

Playbook

According to the official document,

In your playbook steps we’ll typically be using the following pattern for provisioning steps:

- hosts: localhost
  gather_facts: False
  tasks:
    - ...

Intuitivly, all users use same target AWS API because the target might be AWS API server in this case. But, we should use localhost at hosts in your playbook.

Role

Ansible official documents always give us a sample codes and they are so helpful always! So I don’t need to leave a memo actually, but for my reference, I leave it here.

Show the status of an A record - for debugging

# Retrieve the details and save it
- name: Check the status (1/2).
  route53:
    state: get
    zone: myzone.com
    record: front1.myzone.com
    type: A
  register: rec

# Show the data
- name: Check the status (2/2).
  debug:
    msg:  "{{ rec }}"

Add a new A record

- name: Add an A record
  route53:
    state: present
    zone: myzone.com
    record: front2.myzone.com
    type: A
    ttl: 3600
    value: 1.2.3.4

Delete an A record

- name: Retrieve the details for front2.myzone.com
  route53:
      state: get
      zone: myzone.com
      record: front2.myzone.com
      type: A
  register: rec

- name: Delete front2.myzone.com A record using the results from the get command
  route53:
    state: absent
    zone: myzone.com
    record: "{{ rec.set.record }}"
    ttl: "{{ rec.set.ttl }}"
    type: "{{ rec.set.type }}"
    value: "{{ rec.set.value }}"

If you want to delete a record, you should specify not only a record name, but also values should be specified. We use, therefore `two step method, but you can delete in a tasks like below.

 Delete an A record
- name: Delete an A record
  route53:
    state: absent
    zone: myzone.com
    record: front2.myzone.com
    type: A
    ttl: 3600
    value: 1.2.3.4
    wait: yes

Important memo: No “edit multivalue module”

As of April 2020, there is no “modify” parameter, so you can delete a value from multi A values record. Instead, we should use overwrite parameter.

It doesn’t cool enough for multi value

Problem

As of April 2020, when an A record has multi-vaules, it return set.vaules , but the vairable name values is bad name…

https://stackoverflow.com/questions/40281706/cant-read-custom-facts-with-list-array-of-items/47006294

As you mentioned that “{{ansible_local.hdfs.items}}” is printing built-in method items of dict object at 0x7f81f42b2c58.

This is happening because the name items is clashing with the name of some built-in method. So you just need to change the name to something else, you can not use items name in your hdfs.fact file.

Solution

{{ set.value }} returns CSV textline of the IPs. We can use it for multi-value A record. I also used a script values_csv_to_list.sh.

---
# Retrieve the details for
- name: Retrive the details about the A record of front1.myzone.com, which has multi-values in the record.
  route53:
    state: get
    zone: myzone.com
    record: front1.myzone.com
    type: A
  register: rec

- name: Check the IPs in the record.
  debug:
    msg:  "{{ rec.set.value }}"

- name: Run a script (CSV -> list)
  script:
    cmd: values_csv_to_list.sh "{{ rec.set.value }}"
  register: IPs

- name: Add an IP 1.2.3.4.
  set_fact:
    new_IPs_list: "{{ IPs.stdout_lines + ['1.2.3.4'] }}"

- name: Append all items in new_IP_list in commna seperated form.
  debug:
    msg: "{{ new_IPs_list | join(',')}}"

values_csv_to_list.sh

#!/bin/bash

IFS=","
for v in $@
do
  echo $v
done

Tip - Append string in Ansible

Using jinja2 syntac.

- name: Append all items in new_IP_list in commna seperated form.
  debug:
    msg: "{{ new_IP_list | join(',')}}"