class AcmeDnsChallenge(AcmeChallenge): challengeType = challenges.DNS01 def create_certificate(self, csr, issuer_options): """ Creates an ACME certificate. :param csr: :param issuer_options: :return: :raise Exception: """ self.acme = AcmeDnsHandler() authority = issuer_options.get("authority") create_immediately = issuer_options.get("create_immediately", False) acme_client, registration = self.acme.setup_acme_client(authority) domains = self.acme.get_domains(issuer_options) dns_provider = issuer_options.get("dns_provider", {}) if dns_provider: for domain in domains: # Currently, we only support specifying one DNS provider per certificate, even if that # certificate has multiple SANs that may belong to different provid self.acme.dns_providers_for_domain[domain] = [dns_provider] credentials = json.loads(dns_provider.credentials) current_app.logger.debug("Using DNS provider: {0}".format( dns_provider.provider_type)) account_number = credentials.get("account_id") provider_type = dns_provider.provider_type if provider_type == "route53" and not account_number: error = "Route53 DNS Provider {} does not have an account number configured.".format( dns_provider.name) current_app.logger.error(error) raise InvalidConfiguration(error) else: dns_provider = {} account_number = None provider_type = None for domain in domains: self.acme.autodetect_dns_providers(domain) # Create pending authorizations that we'll need to do the creation dns_authorization = authorization_service.create( account_number, domains, provider_type) if not create_immediately: # Return id of the DNS Authorization return None, None, dns_authorization.id pem_certificate, pem_certificate_chain = self.create_certificate_immediately( acme_client, dns_authorization, csr) # TODO add external ID (if possible) return pem_certificate, pem_certificate_chain, None @retry(stop_max_attempt_number=ACME_ADDITIONAL_ATTEMPTS, wait_fixed=5000) def create_certificate_immediately(self, acme_client, order_info, csr): try: order = acme_client.new_order(csr) except WildcardUnsupportedError: metrics.send("create_certificte_immediately_wildcard_unsupported", "counter", 1) raise Exception("The currently selected ACME CA endpoint does" " not support issuing wildcard certificates.") try: authorizations = self.acme.get_authorizations( acme_client, order, order_info) except ClientError: capture_exception() metrics.send("create_certificate_immediately_error", "counter", 1) current_app.logger.error( f"Unable to resolve cert for domains: {', '.join(order_info.domains)}", exc_info=True) return False authorizations = self.acme.finalize_authorizations( acme_client, authorizations) return self.acme.request_certificate(acme_client, authorizations, order) def deploy(self, challenge, acme_client, validation_target): pass def cleanup(self, authorizations, acme_client, validation_target=None): """ Best effort attempt to delete DNS challenges that may not have been deleted previously. This is usually called on an exception :param authorizations: all the authorizations to be cleaned up :param acme_client: an already bootstrapped acme_client, to avoid passing all issuer_options and so on :param validation_target: Unused right now :return: """ acme = AcmeDnsHandler() acme.cleanup_dns_challenges(acme_client, authorizations)