Skip to content

Instantly share code, notes, and snippets.

@ngoue
Last active November 22, 2021 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ngoue/fae88aefb2eca5f6a489cd037c1a34ff to your computer and use it in GitHub Desktop.
Save ngoue/fae88aefb2eca5f6a489cd037c1a34ff to your computer and use it in GitHub Desktop.
Dynamic DNS with Route53
#! /usr/bin/env python3
"""
Dynamic DNS - Route53
Check the current IP address for this device and compare it with the DNS record
in Route53. If it's different, update the DNS record!
"""
import logging
import os
import re
import sys
import boto3
import requests
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S"
)
LOG = logging.getLogger('dynamic-dns')
RE_IP_ADDRESS = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
HOSTED_ZONE_ID = os.getenv('HOSTED_ZONE_ID')
RECORD_NAME = os.getenv('RECORD_NAME')
if __name__ == '__main__':
LOG.debug('Starting dynamic-dns')
# Require HostedZone ID
LOG.debug('Verifying HostedZone ID')
if HOSTED_ZONE_ID is None:
LOG.warning('Missing HostedZone ID')
sys.exit(1)
# Require HostedZone ID
LOG.debug('Verifying record name')
if RECORD_NAME is None:
LOG.warning('Missing record name')
sys.exit(1)
# Check the current public IP address
LOG.debug('Retrieving current public IP address')
current_ip = requests.get('http://checkip.amazonaws.com').text.strip()
LOG.debug('Current public IP address: %s', current_ip)
# Validate the current public IP address
LOG.debug('Validating current public IP address')
if not RE_IP_ADDRESS.match(current_ip):
LOG.warning('Invalid IP address: %s', current_ip)
sys.exit(2)
# Cross-check the current DNS record
LOG.debug('Retrieving current DNS')
route53 = boto3.client('route53')
all_records = route53.list_resource_record_sets(
HostedZoneId=HOSTED_ZONE_ID
).get('ResourceRecordSets', [])
current_record = None
for record in all_records:
if record['Name'] == RECORD_NAME:
current_record = record
break
# Check for changes
LOG.debug('Checking current DNS against current IP address')
if current_record['ResourceRecords'][0]['Value'] == current_ip:
LOG.info('DNS is up-to-date. Exiting...')
sys.exit()
# Update the DNS
LOG.debug('Updating DNS')
route53.change_resource_record_sets(
HostedZoneId=HOSTED_ZONE_ID,
ChangeBatch={
'Comment': 'Updated using dynamic_dns_route53.py',
'Changes': [{
'Action': 'UPSERT',
'ResourceRecordSet': {
'Name': record['Name'],
'Type': record['Type'],
'TTL': 300,
'ResourceRecords': [{
'Value': current_ip
}]
}
}]
}
)
LOG.info('Updated DNS successfully: %s', current_ip)
sys.exit()
@ngoue
Copy link
Author

ngoue commented Nov 22, 2021

Instructions

  1. Install this script onto any device on your network with access to the public interwebs
  2. pip3 install requests boto3
  3. Configure AWS credentials via a profile
  4. Add the following line to your device's crontab
* * * * * AWS_PROFILE=profile HOSTED_ZONE_ID=zone_id RECORD_NAME=record_name /path/to/python3 /path/to/dynamic_dns_route53.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment