1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-26 07:41:33 +03:00

ACMEv2 support for Route53 plugin

This commit is contained in:
Joona Hoikkala
2018-03-04 16:24:42 +02:00
committed by Brad Warren
parent 31805c5a5f
commit fe682e779b
2 changed files with 75 additions and 5 deletions

View File

@@ -85,9 +85,29 @@ class Authenticator(dns_common.DNSAuthenticator):
zones.sort(key=lambda z: len(z[0]), reverse=True)
return zones[0][1]
def _get_validation_rrset(self, zone_id, validation_domain_name):
validation_domain_name += "."
records = self.r53.list_resource_record_sets(HostedZoneId=zone_id)
for record in records["ResourceRecordSets"]:
if record["Name"] == validation_domain_name and record["Type"] == "TXT":
return record["ResourceRecords"]
return []
def _change_txt_record(self, action, validation_domain_name, validation):
zone_id = self._find_zone_id_for_domain(validation_domain_name)
rrecords = self._get_validation_rrset(zone_id, validation_domain_name)
challenge = {"Value": '"{0}"'.format(validation)}
if action == "DELETE":
if len(rrecords) > 1:
# Need to update instead, as we're not deleting the rrset
action = "UPSERT"
# Remove the record being deleted from the list
rrecords = [rr for rr in rrecords if rr != challenge]
else:
if challenge not in rrecords:
rrecords.append(challenge)
response = self.r53.change_resource_record_sets(
HostedZoneId=zone_id,
ChangeBatch={
@@ -99,11 +119,7 @@ class Authenticator(dns_common.DNSAuthenticator):
"Name": validation_domain_name,
"Type": "TXT",
"TTL": self.ttl,
"ResourceRecords": [
# For some reason TXT records need to be
# manually quoted.
{"Value": '"{0}"'.format(validation)}
],
"ResourceRecords": rrecords,
}
}
]

View File

@@ -178,6 +178,9 @@ class ClientTest(unittest.TestCase):
def test_change_txt_record(self):
self.client._find_zone_id_for_domain = mock.MagicMock()
self.client._get_validation_rrset = mock.MagicMock(
return_value=[]
)
self.client.r53.change_resource_record_sets = mock.MagicMock(
return_value={"ChangeInfo": {"Id": 1}})
@@ -186,6 +189,57 @@ class ClientTest(unittest.TestCase):
call_count = self.client.r53.change_resource_record_sets.call_count
self.assertEqual(call_count, 1)
def test_change_txt_record_multirecord(self):
self.client._find_zone_id_for_domain = mock.MagicMock()
self.client._get_validation_rrset = mock.MagicMock()
self.client._get_validation_rrset.return_value = [
{"Value": "\"pre-existing-value\""},
{"Value": "\"pre-existing-value-two\""},
]
self.client.r53.change_resource_record_sets = mock.MagicMock(
return_value={"ChangeInfo": {"Id": 1}})
self.client._change_txt_record("DELETE", DOMAIN, "pre-existing-value")
call_count = self.client.r53.change_resource_record_sets.call_count
call_args = self.client.r53.change_resource_record_sets.call_args_list[0][1]
call_args_batch = call_args["ChangeBatch"]["Changes"][0]
self.assertEqual(call_args_batch["Action"], "UPSERT")
self.assertEqual(
call_args_batch["ResourceRecordSet"]["ResourceRecords"],
[{"Value": "\"pre-existing-value-two\""}])
self.assertEqual(call_count, 1)
def test_get_validation_rrset(self):
self.client.r53.list_resource_record_sets = mock.MagicMock(
return_value={"ResourceRecordSets": [
{"Name": "_acme-challenge.example.org.",
"Type": "TXT",
"ResourceRecords": [
{"Value": "\"validation-token\""},
{"Value": "\"another-validation-token\""},
],
},
{"Name": "_acme-challenge.example.org.",
"Type": "NS",
"ResourceRecords": [
{"Value": "ns1.example.com"},
],
}
]})
rrset = self.client._get_validation_rrset("zoneid",
"_acme-challenge.example.org")
self.assertEquals(len(rrset), 2)
self.assertTrue({"Value": "\"another-validation-token\""} in rrset)
def test_get_validation_rrset_empty(self):
self.client.r53.list_resource_record_sets = mock.MagicMock(
return_value={"ResourceRecordSets": []})
rrset = self.client._get_validation_rrset("zoneid",
"_acme-challenge.example.org")
self.assertEquals(rrset, [])
def test_wait_for_change(self):
self.client.r53.get_change = mock.MagicMock(
side_effect=[{"ChangeInfo": {"Status": "PENDING"}},