commit 93081cd6fc88959607847f45a470904b9ead0135 Author: Paco Hope Date: Mon Feb 6 09:43:06 2017 +0000 Initial commit diff --git a/Dynamic DNS blog.docx b/Dynamic DNS blog.docx new file mode 100644 index 0000000..61b7056 Binary files /dev/null and b/Dynamic DNS blog.docx differ diff --git a/auto-update-r53.py b/auto-update-r53.py new file mode 100644 index 0000000..c5d240a --- /dev/null +++ b/auto-update-r53.py @@ -0,0 +1,142 @@ +#!/usr/bin/python +# +# Dynamically update DNS records when the EC2 instance boots. +# Requires boto3 installed on the instance. +# Requries an IAM policy attached to an instance role. +# + +import urllib2 +from boto3.session import Session +import boto3 +import datetime + +def getRegion(): + url = "http://169.254.169.254/2009-04-04/meta-data/placement/availability-zone" + try: + resp = urllib2.urlopen(urllib2.Request(url)) + # Region will be a string like eu-central-1a. This chops the last character off. + region = resp.read()[:-1] + except urllib2.HTTPError as e: + if e.code == 404: + return None + if e.code == 500: + return None + raise + + return region + +def getInstanceId(): + url = "http://169.254.169.254/2009-04-04/meta-data/instance-id" + try: + resp = urllib2.urlopen(urllib2.Request(url)) + instanceid = resp.read() + except urllib2.HTTPError as e: + if e.code == 404: + return None + if e.code == 500: + return None + raise + + return instanceid + +def getPublicIP(): + url = "http://169.254.169.254/2009-04-04/meta-data/public-ipv4" + try: + resp = urllib2.urlopen(urllib2.Request(url)) + value = resp.read() + except urllib2.HTTPError as e: + if e.code == 404: + return None + if e.code == 500: + return None + raise + + return value + +# Get region and instance ID +myregion = getRegion() +myinstance = getInstanceId() +myipv4 = getPublicIP() + +if( myregion == None or myinstance == None or myipv4 == None): + print "ERROR: Could not get instance metadata. Abort." + exit( -1 ) + +# Connect to EC2 and get the instance handle for this instance +ec2 = boto3.resource('ec2', region_name=myregion) +instance = ec2.Instance(myinstance) + +# Grab the tags associated with this instance +mytags = instance.tags +dnsname = None + +# Get host tag or bail +for tag in instance.tags: + if( tag['Key'] == 'dnsname'): + dnsname = tag['Value'] + +if (dnsname == None): + print "Did not find dnsname tag. " + exit( -1 ) + +# Get just the domain part of dnsname +myzone = dnsname.partition(".")[2] + +# Get zoneid for zone or bail +session = Session(region_name=myregion) +client = session.client('route53') +# Note: if you have more than 100 hosted zones, there's a chance that +# the zone you need won't be returned in response to the first call +# to list_hosted_zones(). The next loop will fail to find your zone. +# +# If this applies to you, you have to rewrite this section to use +# pagination to iterate over the collection of returned domains, +# looking for the one you want. That extension is left as an +# exercise for the reader. +myzoneid = None +zones = client.list_hosted_zones() + +# Route53 will return zones in canonical form with the trailing dot. +# e.g.: "ec2.example.com." +# It's likely that people will enter dnsnames in the tags without the +# trailing dot, so this helps make the match either way. +for zone in zones['HostedZones']: + if( (zone['Name'] == myzone) or (zone['Name'] == myzone + ".")): + myzoneid = zone['Id'] + +if( myzoneid == '' ): + # didn't find the zone + print "ERROR: Did not find " + myzone + " among the hosted zones." + exit( -1 ) + +# Create record set update +print "setting " + dnsname + " to " + myipv4 +now = datetime.datetime.now() + +response = client.change_resource_record_sets( + HostedZoneId=myzoneid, + ChangeBatch={ + 'Comment': 'Instance ' + myinstance + ' boot at ' + now.strftime("%Y-%m-%d %H:%M"), + 'Changes': [ + { + 'Action': 'UPSERT', + 'ResourceRecordSet': { + 'TTL': 300, + 'Name': dnsname, + 'Type': 'A', + 'ResourceRecords': [ + { + 'Value': myipv4 + }, + ] + } + }, + ] + } +) + +# Check for error. +if( response['ResponseMetadata']['HTTPStatusCode'] != 200 ): + print "ERROR updating Route53" + print response + exit( -1 ) diff --git a/dns-update-policy.json b/dns-update-policy.json new file mode 100644 index 0000000..89c3583 --- /dev/null +++ b/dns-update-policy.json @@ -0,0 +1,26 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "route53:ChangeResourceRecordSets", + "route53:GetHostedZone", + "route53:ListResourceRecordSets" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:route53:::hostedzone/[ZONEID]", + ] + }, + { + "Action": [ + "route53:ListHostedZones", + "ec2:DescribeInstances" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] +}