def revoke_certificate(self, certificate, reason): self.acme = AcmeDnsHandler() crl_reason = CRLReason.unspecified if "crl_reason" in reason: crl_reason = CRLReason[reason["crl_reason"]] return self.acme.revoke_certificate(certificate, crl_reason.value)
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) dns_provider = issuer_options.get("dns_provider", {}) if dns_provider: dns_provider_options = dns_provider.options credentials = json.loads(dns_provider.credentials) current_app.logger.debug("Using DNS provider: {0}".format( dns_provider.provider_type)) dns_provider_plugin = __import__(dns_provider.provider_type, globals(), locals(), [], 1) 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 = {} dns_provider_options = None account_number = None provider_type = None domains = self.acme.get_domains(issuer_options) if not create_immediately: # Create pending authorizations that we'll need to do the creation dns_authorization = authorization_service.create( account_number, domains, provider_type) # Return id of the DNS Authorization return None, None, dns_authorization.id authorizations = self.acme.get_authorizations( acme_client, account_number, domains, dns_provider_plugin, dns_provider_options, ) self.acme.finalize_authorizations( acme_client, account_number, dns_provider_plugin, authorizations, dns_provider_options, ) pem_certificate, pem_certificate_chain = self.acme.request_certificate( acme_client, authorizations, csr) # TODO add external ID (if possible) return pem_certificate, pem_certificate_chain, None
def get_all_zones(): """ Retrieves all DNS providers from the database. Refreshes the zones associated with each DNS provider """ print("[+] Starting dns provider zone lookup and configuration.") dns_providers = get_all_dns_providers() acme_dns_handler = AcmeDnsHandler() function = f"{__name__}.{sys._getframe().f_code.co_name}" log_data = { "function": function, "message": "", } for dns_provider in dns_providers: try: zones = acme_dns_handler.get_all_zones(dns_provider) set_domains(dns_provider, zones) except Exception as e: print("[+] Error with DNS Provider {}: {}".format( dns_provider.name, e)) log_data[ "message"] = f"get all zones failed for {dns_provider} {e}." capture_exception(extra=log_data) status = SUCCESS_METRIC_STATUS metrics.send("get_all_zones", "counter", 1, metric_tags={"status": status}) print("[+] Done with dns provider zone lookup and configuration.")
def cleanup(self, authorizations, acme_client, validation_target): """ 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)
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
def get_ordered_certificate(self, pending_cert): self.acme = AcmeDnsHandler() acme_client, registration = self.acme.setup_acme_client(pending_cert.authority) order_info = authorization_service.get(pending_cert.external_id) if pending_cert.dns_provider_id: dns_provider = dns_provider_service.get(pending_cert.dns_provider_id) for domain in order_info.domains: # Currently, we only support specifying one DNS provider per certificate, even if that # certificate has multiple SANs that may belong to different providers. self.acme.dns_providers_for_domain[domain] = [dns_provider] else: for domain in order_info.domains: self.acme.autodetect_dns_providers(domain) try: order = acme_client.new_order(pending_cert.csr) except WildcardUnsupportedError: metrics.send("get_ordered_certificate_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("get_ordered_certificate_error", "counter", 1) current_app.logger.error( f"Unable to resolve pending cert: {pending_cert.name}", exc_info=True ) return False authorizations = self.acme.finalize_authorizations(acme_client, authorizations) pem_certificate, pem_certificate_chain = self.acme.request_certificate( acme_client, authorizations, order ) cert = { "body": "\n".join(str(pem_certificate).splitlines()), "chain": "\n".join(str(pem_certificate_chain).splitlines()), "external_id": str(pending_cert.external_id), } return cert
def get_ordered_certificates(self, pending_certs): self.acme = AcmeDnsHandler() self.acme_dns_challenge = AcmeDnsChallenge() pending = [] certs = [] for pending_cert in pending_certs: try: acme_client, registration = self.acme.setup_acme_client( pending_cert.authority ) order_info = authorization_service.get(pending_cert.external_id) if pending_cert.dns_provider_id: dns_provider = dns_provider_service.get( pending_cert.dns_provider_id ) for domain in order_info.domains: # Currently, we only support specifying one DNS provider per certificate, even if that # certificate has multiple SANs that may belong to different providers. self.acme.dns_providers_for_domain[domain] = [dns_provider] else: for domain in order_info.domains: self.acme.autodetect_dns_providers(domain) try: order = acme_client.new_order(pending_cert.csr) except WildcardUnsupportedError: capture_exception() metrics.send( "get_ordered_certificates_wildcard_unsupported_error", "counter", 1, ) raise Exception( "The currently selected ACME CA endpoint does" " not support issuing wildcard certificates." ) authorizations = self.acme.get_authorizations( acme_client, order, order_info ) pending.append( { "acme_client": acme_client, "authorizations": authorizations, "pending_cert": pending_cert, "order": order, } ) except (ClientError, ValueError, Exception) as e: capture_exception() metrics.send( "get_ordered_certificates_pending_creation_error", "counter", 1 ) current_app.logger.error( f"Unable to resolve pending cert: {pending_cert}", exc_info=True ) error = e if globals().get("order") and order: error += f" Order uri: {order.uri}" certs.append( {"cert": False, "pending_cert": pending_cert, "last_error": e} ) for entry in pending: try: entry["authorizations"] = self.acme.finalize_authorizations( entry["acme_client"], entry["authorizations"] ) pem_certificate, pem_certificate_chain = self.acme.request_certificate( entry["acme_client"], entry["authorizations"], entry["order"] ) cert = { "body": "\n".join(str(pem_certificate).splitlines()), "chain": "\n".join(str(pem_certificate_chain).splitlines()), "external_id": str(entry["pending_cert"].external_id), } certs.append({"cert": cert, "pending_cert": entry["pending_cert"]}) except (PollError, AcmeError, Exception) as e: capture_exception() metrics.send("get_ordered_certificates_resolution_error", "counter", 1) order_url = order.uri error = f"{e}. Order URI: {order_url}" current_app.logger.error( f"Unable to resolve pending cert: {pending_cert}. " f"Check out {order_url} for more information.", exc_info=True, ) certs.append( { "cert": False, "pending_cert": entry["pending_cert"], "last_error": error, } ) # Ensure DNS records get deleted self.acme_dns_challenge.cleanup( entry["authorizations"], entry["acme_client"] ) return certs
def revoke_certificate(self, certificate, comments): self.acme = AcmeDnsHandler() return self.acme.revoke_certificate(certificate)