mirror of
https://github.com/certbot/certbot.git
synced 2026-06-03 13:59:02 -04:00
First working iteration
This commit is contained in:
parent
c4364f82fb
commit
1a5f09f4cf
2 changed files with 78 additions and 45 deletions
|
|
@ -1,23 +1,21 @@
|
|||
"""Route53 Let's Encrypt authenticator plugin."""
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import zope.component
|
||||
import zope.interface
|
||||
|
||||
import boto3
|
||||
|
||||
from acme import challenges
|
||||
|
||||
from letsencrypt import errors
|
||||
from letsencrypt import interfaces
|
||||
from letsencrypt.plugins import common
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TTL = 30
|
||||
|
||||
class Authenticator(common.Plugin):
|
||||
zope.interface.implements(interfaces.IAuthenticator)
|
||||
zope.interface.classProvides(interfaces.IPluginFactory)
|
||||
|
|
@ -44,50 +42,85 @@ class Authenticator(common.Plugin):
|
|||
responses.append(self._perform_single(achall))
|
||||
return responses
|
||||
|
||||
def _find_zone(self, r53, domain):
|
||||
return max(
|
||||
(
|
||||
zone for zone in r53.list_hosted_zones()["HostedZones"]
|
||||
if (domain+".").endswith("."+zone["Name"])
|
||||
),
|
||||
key=lambda zone: len(zone["Name"]),
|
||||
)
|
||||
|
||||
|
||||
def _perform_single(self, achall):
|
||||
# provision the TXT record, using the domain name given. Assumes the hosted zone exits, else fails the challenge
|
||||
response, validation = achall.response_and_validation()
|
||||
r53 = boto3.client('route53')
|
||||
logger.info("Doing validation for " + response.domain)
|
||||
listResponse = r53.list_hosted_zones_by_name(DNSName=response.domain)
|
||||
matches = listResponse.HostedZones;
|
||||
if matches.size != 0:
|
||||
logger.error("Route53 returned " + mathces.size + " matching hosted zones. Expected exactly one. Auth canceled.")
|
||||
return None
|
||||
else:
|
||||
r53.change_resource_record_sets(HostedZoneId=matches[0].Id,
|
||||
ChangeBatch={
|
||||
'Comment': 'Let\'s Entcrypt Change',
|
||||
'Changes': [
|
||||
{
|
||||
'Action': 'UPSERT',
|
||||
'ResourceRecordSet': {
|
||||
'Name': achall.validation_domain_name(),
|
||||
'Type': 'TXT',
|
||||
'TTL': 300,
|
||||
'ResourceRecords': [
|
||||
{
|
||||
'Value': validation
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
logger.info("Doing validation for " + achall.domain)
|
||||
listResponse = r53.list_hosted_zones_by_name(DNSName=achall.domain)
|
||||
|
||||
if response.simple_verify(
|
||||
achall.chall, achall.domain,
|
||||
achall.account_key.public_key(), self.config.http01_port):
|
||||
return response
|
||||
else:
|
||||
logger.error(
|
||||
"Self-verify of challenge failed, authorization abandoned!")
|
||||
try:
|
||||
zone = self._find_zone(r53, achall.domain)
|
||||
except ValueError as e:
|
||||
logger.error("Unable to find matching Route53 zone for domain " + achall.domain)
|
||||
return None
|
||||
|
||||
response, validation = achall.response_and_validation()
|
||||
self._excute_r53_action(r53, achall, zone, validation, 'UPSERT', wait_for_change=True)
|
||||
|
||||
for _ in xrange(TTL*2):
|
||||
if response.simple_verify(
|
||||
achall.chall,
|
||||
achall.domain,
|
||||
achall.account_key.public_key(),
|
||||
):
|
||||
break
|
||||
logger.info("Waiting for DNS propagation...")
|
||||
time.sleep(1)
|
||||
else:
|
||||
logger.error("Unable to verify domain " + achall.domain)
|
||||
return None
|
||||
|
||||
return response
|
||||
|
||||
def cleanup(self, achalls):
|
||||
# pylint: disable=missing-docstring,no-self-use,unused-argument
|
||||
#TODO:Cleanup record
|
||||
# pylint: disable=missing-docstring
|
||||
r53 = boto3.client('route53')
|
||||
#for achall in achalls:
|
||||
# r53.delete_object(Bucket=self.conf('s3-bucket'), Key=achall.chall.path[1:])
|
||||
for achall in achalls:
|
||||
try:
|
||||
zone = self._find_zone(r53, achall.domain)
|
||||
except ValueError:
|
||||
logger.warn("Unable to find zone for " + achall.domain + ". Skipping cleanup.")
|
||||
continue
|
||||
|
||||
_, validation = achall.response_and_validation()
|
||||
self._excute_r53_action(r53, achall, zone, validation, 'DELETE')
|
||||
return None
|
||||
|
||||
|
||||
def _excute_r53_action(self, r53, achall, zone, validation, action, wait_for_change=False):
|
||||
response = r53.change_resource_record_sets(
|
||||
HostedZoneId=zone["Id"],
|
||||
ChangeBatch={
|
||||
'Comment': 'Let\'s Encrypt ' + action,
|
||||
'Changes': [
|
||||
{
|
||||
'Action': action,
|
||||
'ResourceRecordSet': {
|
||||
'Name': achall.validation_domain_name(achall.domain),
|
||||
'Type': 'TXT',
|
||||
'TTL': TTL,
|
||||
'ResourceRecords': [
|
||||
{
|
||||
'Value': '"' + validation + '"',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
if wait_for_change:
|
||||
while r53.get_change(Id=response["ChangeInfo"]["Id"])["ChangeInfo"]["Status"] == "PENDING":
|
||||
logger.info("Waiting for " + action + " to propagate...")
|
||||
time.sleep(1)
|
||||
|
|
|
|||
4
setup.py
4
setup.py
|
|
@ -6,8 +6,8 @@ from setuptools import find_packages
|
|||
version = '0.1.3'
|
||||
|
||||
install_requires = [
|
||||
'acme>=0.1.1',
|
||||
'letsencrypt>=0.1.1',
|
||||
'acme>=0.9.0.dev0',
|
||||
'letsencrypt>=0.9.0.dev0',
|
||||
'PyOpenSSL',
|
||||
'pyparsing>=1.5.5', # Python3 support; perhaps unnecessary?
|
||||
'setuptools', # pkg_resources
|
||||
|
|
|
|||
Loading…
Reference in a new issue