Skip to content

Instantly share code, notes, and snippets.

@pkoch
Created March 17, 2017 11:35
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 pkoch/ef7d190310f40ee3d2c191c6a4800397 to your computer and use it in GitHub Desktop.
Save pkoch/ef7d190310f40ee3d2c191c6a4800397 to your computer and use it in GitHub Desktop.
diff --git a/certbot_route53/authenticator.py b/certbot_route53/authenticator.py
index fe87f96..b8d020a 100644
--- a/certbot_route53/authenticator.py
+++ b/certbot_route53/authenticator.py
@@ -39,6 +39,7 @@ class Authenticator(common.Plugin):
def __init__(self, *args, **kwargs):
super(Authenticator, self).__init__(*args, **kwargs)
+ self.r53 = boto3.client("route53")
def prepare(self): # pylint: disable=missing-docstring,no-self-use
pass # pragma: no cover
@@ -52,32 +53,27 @@ class Authenticator(common.Plugin):
def perform(self, achalls): # pylint: disable=missing-docstring
try:
- change_ids = [self._create_single(achall) for achall in achalls]
- # Sleep for at least the TTL, to ensure that any records cached by
- # the ACME server after previous validation attempts are gone. In
- # most cases we'll need to wait at least this long for the Route53
- # records to propagate, so this doesn't delay us much.
- time.sleep(TTL)
+ change_ids = [
+ self._change_txt_record("UPSERT", achall)
+ for achall in achalls
+ ]
+
for change_id in change_ids:
self._wait_for_change(change_id)
+
+ # Sleep for at least the TTL, to ensure that any records cached by
+ # the ACME server after previous validation attempts are gone.
+ time.sleep(TTL)
+
return [achall.response(achall.account_key) for achall in achalls]
- except NoCredentialsError:
- raise Exception("No AWS Route53 credentials found. " + INSTRUCTIONS)
- except ClientError as e:
- raise Exception(str(e) + "\n" + INSTRUCTIONS)
+
+ except (NoCredentialsError, ClientError) as e:
+ e.args = ("\n".join([str(e), INSTRUCTIONS]),)
+ raise
def cleanup(self, achalls): # pylint: disable=missing-docstring
for achall in achalls:
- name = achall.validation_domain_name(achall.domain)
- value = achall.validation(achall.account_key)
- self._change_txt_record("DELETE", name, value)
-
- def _create_single(self, achall):
- """Create a TXT record, return a change_id"""
- name = achall.validation_domain_name(achall.domain)
- value = achall.validation(achall.account_key)
- change_id = self._change_txt_record("UPSERT", name, value)
- return change_id
+ self._change_txt_record("DELETE", achall)
def _find_zone_id_for_domain(self, domain):
"""Find the zone id responsible a given FQDN.
@@ -85,14 +81,14 @@ class Authenticator(common.Plugin):
That is, the id for the zone whose name is the longest parent of the
domain.
"""
- client = boto3.client("route53")
- paginator = client.get_paginator("list_hosted_zones")
+ paginator = self.r53.get_paginator("list_hosted_zones")
zones = []
target_labels = domain.rstrip(".").split(".")
for page in paginator.paginate():
for zone in page["HostedZones"]:
if zone["Config"]["PrivateZone"]:
continue
+
candidate_labels = zone["Name"].rstrip(".").split(".")
if candidate_labels == target_labels[-len(candidate_labels):]:
zones.append((zone["Name"], zone["Id"]))
@@ -109,10 +105,13 @@ class Authenticator(common.Plugin):
zones.sort(key=lambda z: len(z[0]), reverse=True)
return zones[0][1]
- def _change_txt_record(self, action, domain, value):
+ def _change_txt_record(self, action, achall):
+ domain = achall.validation_domain_name(achall.domain)
+ value = achall.validation(achall.account_key)
+
zone_id = self._find_zone_id_for_domain(domain)
- client = boto3.client("route53")
- response = client.change_resource_record_sets(
+
+ response = self.r53.change_resource_record_sets(
HostedZoneId=zone_id,
ChangeBatch={
"Comment": "certbot-route53 certificate validation " + action,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment