Philip Colmer
Philip Colmer

Reputation: 1664

How to get all resource record sets from Route 53 with boto?

I'm writing a script that makes sure that all of our EC2 instances have DNS entries, and all of the DNS entries point to valid EC2 instances.

My approach is to try and get all of the resource records for our domain so that I can iterate through the list when checking for an instance's name.

However, getting all of the resource records doesn't seem to be a very straightforward thing to do! The documentation for GET ListResourceRecordSets seems to suggest it might do what I want and the boto equivalent seems to be get_all_rrsets ... but it doesn't seem to work as I would expect.

For example, if I go:

r53 = boto.connect_route53()
zones = r53.get_zones()
fooA = r53.get_all_rrsets(zones[0][id], name="a")

then I get 100 results. If I then go:

fooB = r53.get_all_rrsets(zones[0][id], name="b")

I get the same 100 results. Have I misunderstood and get_all_rrsets does not map onto ListResourceRecordSets?

Any suggestions on how I can get all of the records out of Route 53?

Update: cli53 (https://github.com/barnybug/cli53/blob/master/cli53/client.py) is able to do this through its feature to export a Route 53 zone in BIND format (cmd_export). However, my Python skills aren't strong enough to allow me to understand how that code works!

Thanks.

Upvotes: 3

Views: 8031

Answers (2)

jitter
jitter

Reputation: 444

this blog post from 2018 has a script which allows exporting in bind format:

#!/usr/bin/env python3
# https://blog.jverkamp.com/2018/03/12/generating-zone-files-from-route53/

import boto3
import sys

route53 = boto3.client('route53')

paginate_hosted_zones = route53.get_paginator('list_hosted_zones')
paginate_resource_record_sets = route53.get_paginator('list_resource_record_sets')

domains = [domain.lower().rstrip('.') for domain in sys.argv[1:]]

for zone_page in paginate_hosted_zones.paginate():
    for zone in zone_page['HostedZones']:
        if domains and not zone['Name'].lower().rstrip('.') in domains:
            continue

        for record_page in paginate_resource_record_sets.paginate(HostedZoneId = zone['Id']):
            for record in record_page['ResourceRecordSets']:
                if record.get('ResourceRecords'):
                    for target in record['ResourceRecords']:
                        print(record['Name'], record['TTL'], 'IN', record['Type'], target['Value'], sep = '\t')
                elif record.get('AliasTarget'):
                    print(record['Name'], 300, 'IN', record['Type'], record['AliasTarget']['DNSName'], '; ALIAS', sep = '\t')
                else:
                    raise Exception('Unknown record type: {}'.format(record))

usage example:

./export-zone.py mydnszone.aws
mydnszone.aws.  300 IN  A   server.mydnszone.aws.   ; ALIAS
mydnszone.aws.  86400   IN  CAA 0 iodef "mailto:[email protected]"
mydnszone.aws.  86400   IN  CAA 128 issue "letsencrypt.org"
mydnszone.aws.  86400   IN  MX  10 server.mydnszone.aws.

the output can be saved as a file and/or copied to the clipboard:

AWS - Import zone file button

the Import zone file page allows to paste the data:

AWS - Import zone file

at the time of this writing the script was working fine using python 3.9.

Upvotes: 0

Jim Browne
Jim Browne

Reputation: 131

get_all_rrsets returns a ResourceRecordSets which derives from Python's list class. By default, 100 records are returned. So if you use the result as a list it will have 100 records. What you instead want to do is something like this:

r53records = r53.get_all_rrsets(zones[0][id])
for record in r53records:
    # do something with each record here

Alternatively if you want all of the records in a list:

records = [r for r in r53.get_all_rrsets(zones[0][id]))]

When iterating either with a for loop or list comprehension Boto will fetch the additional records (up to) 100 records at a time as needed.

Upvotes: 5

Related Questions