#!/usr/bin/env python
|
|
|
|
import boto3, sys, time
|
|
from os.path import basename
|
|
import dns.resolver
|
|
|
|
client = boto3.client('route53')
|
|
|
|
name = sys.argv[0]
|
|
fqdn = sys.argv[1]
|
|
challenge = sys.argv[2]
|
|
|
|
bname = basename(name)
|
|
if bname == 'dns_add_route53':
|
|
action = 'UPSERT'
|
|
elif bname == 'dns_del_route53':
|
|
action = 'DELETE'
|
|
else:
|
|
print("No such action: {a}".format(a=bname))
|
|
sys.exit(1)
|
|
|
|
try:
|
|
response = client.list_hosted_zones()
|
|
except Exception as e:
|
|
print("Oops: {e!r}".format(e=e))
|
|
sys.exit(1)
|
|
|
|
zone_id = ""
|
|
zone_list = dict()
|
|
for zone in response['HostedZones']:
|
|
if not zone['Config']['PrivateZone']:
|
|
zone_list[zone['Name']] = zone['Id']
|
|
|
|
for key in sorted(zone_list.keys(), key=len, reverse=True):
|
|
if ".{z}".format(z=key) in ".{z}.".format(z=fqdn):
|
|
zone_id = zone_list[key]
|
|
|
|
if zone_id == "":
|
|
print("We didn't find the zone")
|
|
sys.exit(1)
|
|
|
|
challenge_fqdn = "_acme-challenge.{f}".format(f=fqdn)
|
|
try:
|
|
response = client.change_resource_record_sets(
|
|
HostedZoneId=zone_id,
|
|
ChangeBatch={
|
|
'Comment': 'getssl/Letsencrypt verification',
|
|
'Changes': [
|
|
{
|
|
'Action': action,
|
|
'ResourceRecordSet': {
|
|
'Name': challenge_fqdn,
|
|
'Type': 'TXT',
|
|
'TTL': 300,
|
|
'ResourceRecords': [{'Value': "\"{c}\"".format(c=challenge)}]
|
|
}
|
|
},
|
|
]
|
|
}
|
|
)
|
|
except Exception as e:
|
|
print("Oops: {e!r}".format(e=e))
|
|
sys.exit(1)
|
|
|
|
waiting = 0
|
|
if action == 'UPSERT':
|
|
# Wait until we see the record before returning. The ACME server's timeout is too short.
|
|
# But only if we're adding the record. Don't care how long it takes to delete.
|
|
while (True):
|
|
try:
|
|
my_resolver = dns.resolver.Resolver(configure=False)
|
|
my_resolver.nameservers = ['8.8.8.8', '8.8.4.4']
|
|
results = my_resolver.resolve(challenge_fqdn, 'TXT')
|
|
data = str(results.response.answer[0][0]).strip('\"')
|
|
if data == challenge:
|
|
print("found {f} entry".format(f=challenge_fqdn))
|
|
else:
|
|
print("found {f} entry but it has bad data: {d}".format(f=challenge_fqdn,
|
|
d=data))
|
|
break
|
|
|
|
except dns.resolver.NXDOMAIN:
|
|
waiting += 10
|
|
print("Didn't find {f} entry yet, sleeping... ({w}s)".format(f=challenge_fqdn,
|
|
w=waiting))
|
|
time.sleep(10)
|
|
pass
|