lemur_acme package

lemur_acme Module

acme_handlers Module

class lemur.plugins.lemur_acme.acme_handlers.AcmeDnsHandler

Bases: lemur.plugins.lemur_acme.acme_handlers.AcmeHandler

autodetect_dns_providers(domain)

Get DNS providers associated with a domain when it has not been provided for certificate creation. :param domain: :return: dns_providers: List of DNS providers that have the correct zone.

cleanup_dns_challenges(acme_client, authorizations)

Best effort attempt to delete DNS challenges that may not have been deleted previously. This is usually called on an exception

Parameters
  • acme_client

  • account_number

  • dns_provider

  • authorizations

  • dns_provider_options

Returns

complete_dns_challenge(acme_client, authz_record)
finalize_authorizations(acme_client, authorizations)
get_all_zones(dns_provider)
get_authorizations(acme_client, order, order_info)

The list can be empty if all hostname validations are still valid

get_cname(domain)
Parameters

domain – Domain name to look up a CNAME for.

Returns

First CNAME target or False if no CNAME record exists.

get_dns_challenges(host, authorizations)

Get dns challenges for provided domain Also indicate if the hostname is already validated

get_dns_provider(type)
start_dns_challenge(acme_client, account_number, domain, target_domain, dns_provider, order, dns_provider_options)
class lemur.plugins.lemur_acme.acme_handlers.AcmeHandler

Bases: object

extract_cert_and_chain(fullchain_pem, alternative_fullchains_pem, preferred_issuer=None)
get_domains(options)

Fetches all domains currently requested :param options: :return:

log_remaining_validation(authorizations, acme_account)
maybe_add_extension(host, dns_provider_options)
request_certificate(acme_client, authorizations, order)
reuse_account(authority)
revoke_certificate(certificate, crl_reason=0)
setup_acme_client(authority)
strip_wildcard(host)

Removes the leading wildcard and returns Host and whether it was removed or not (True/False)

class lemur.plugins.lemur_acme.acme_handlers.AuthorizationRecord(domain, target_domain, authz, dns_challenge, change_id, cname_delegation)

Bases: object

challenge_types Module

class lemur.plugins.lemur_acme.challenge_types.AcmeChallenge

Bases: object

This is the base class, all ACME challenges will need to extend, allowing for future extendability

cleanup(challenge, acme_client, validation_target)

Ideally the challenge should be cleaned up, after the validation is done :param challenge: Needed to identify the challenge to be removed :param acme_client: an already bootstrapped acme_client, to avoid passing all issuer_options and so on :param validation_target: Needed to remove the validation

create_certificate(csr, issuer_options)

Create the new certificate, using the provided CSR and issuer_options. Right now this is basically a copy of the create_certificate methods in the AcmeHandlers, but should be cleaned and tried to make use of the deploy and cleanup methods

Parameters
  • csr

  • issuer_options

Returns

deploy(challenge, acme_client, validation_target)

In here the challenge validation is fetched and deployed somewhere that it can be validated by the provider

Parameters
  • self

  • challenge – the challenge object, must match for the challenge implementation

  • acme_client – an already bootstrapped acme_client, to avoid passing all issuer_options and so on

  • validation_target – an identifier for the validation target, e.g. the name of a DNS provider

exception lemur.plugins.lemur_acme.challenge_types.AcmeChallengeMissmatchError(*args, **kwargs)

Bases: lemur.exceptions.LemurException

class lemur.plugins.lemur_acme.challenge_types.AcmeDnsChallenge

Bases: lemur.plugins.lemur_acme.challenge_types.AcmeChallenge

cleanup(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

Parameters
  • authorizations – all the authorizations to be cleaned up

  • acme_client – an already bootstrapped acme_client, to avoid passing all issuer_options and so on

  • validation_target – Unused right now

Returns

create_certificate(csr, issuer_options)

Creates an ACME certificate.

Parameters
  • csr

  • issuer_options

Returns

raise Exception

create_certificate_immediately(acme_client, order_info, csr)
deploy(challenge, acme_client, validation_target)

In here the challenge validation is fetched and deployed somewhere that it can be validated by the provider

Parameters
  • self

  • challenge – the challenge object, must match for the challenge implementation

  • acme_client – an already bootstrapped acme_client, to avoid passing all issuer_options and so on

  • validation_target – an identifier for the validation target, e.g. the name of a DNS provider

class lemur.plugins.lemur_acme.challenge_types.AcmeHttpChallenge

Bases: lemur.plugins.lemur_acme.challenge_types.AcmeChallenge

cleanup(token_path, validation_target)

Ideally the challenge should be cleaned up, after the validation is done :param challenge: Needed to identify the challenge to be removed :param acme_client: an already bootstrapped acme_client, to avoid passing all issuer_options and so on :param validation_target: Needed to remove the validation

create_certificate(csr, issuer_options)

Creates an ACME certificate using the HTTP-01 challenge.

Parameters
  • csr

  • issuer_options

Returns

raise Exception

deploy(challenge, acme_client, validation_target)

In here the challenge validation is fetched and deployed somewhere that it can be validated by the provider

Parameters
  • self

  • challenge – the challenge object, must match for the challenge implementation

  • acme_client – an already bootstrapped acme_client, to avoid passing all issuer_options and so on

  • validation_target – an identifier for the validation target, e.g. the name of a DNS provider

cloudflare Module

lemur.plugins.lemur_acme.cloudflare.cf_api_call()
lemur.plugins.lemur_acme.cloudflare.create_txt_record(host, value, account_number)
lemur.plugins.lemur_acme.cloudflare.delete_txt_record(change_ids, account_number, host, value)
lemur.plugins.lemur_acme.cloudflare.find_zone_id(host)
lemur.plugins.lemur_acme.cloudflare.wait_for_dns_change(change_id, account_number=None)

dyn Module

lemur.plugins.lemur_acme.dyn.create_txt_record(domain, token, account_number)
lemur.plugins.lemur_acme.dyn.delete_acme_txt_records(domain)
lemur.plugins.lemur_acme.dyn.delete_txt_record(change_id, account_number, domain, token)
lemur.plugins.lemur_acme.dyn.get_authoritative_nameserver(domain)
lemur.plugins.lemur_acme.dyn.get_dynect_session()
lemur.plugins.lemur_acme.dyn.get_zone_name(domain)
lemur.plugins.lemur_acme.dyn.get_zones(account_number)
lemur.plugins.lemur_acme.dyn.wait_for_dns_change(change_id, account_number=None)

plugin Module

class lemur.plugins.lemur_acme.plugin.ACMEHttpIssuerPlugin(*args, **kwargs)

Bases: lemur.plugins.bases.issuer.IssuerPlugin

author = 'Netflix'
author_url = 'https://github.com/netflix/lemur.git'
cancel_ordered_certificate(pending_cert, **kwargs)
static create_authority(options)

Creates an authority, this authority is then used by Lemur to allow a user to specify which Certificate Authority they want to sign their certificate.

Parameters

options

Returns

create_certificate(csr, issuer_options)

Creates an ACME certificate using the HTTP-01 challenge.

Parameters
  • csr

  • issuer_options

Returns

raise Exception

description = "Enables the creation of certificates via ACME CAs (including Let's Encrypt), using the HTTP-01 challenge"
options = [{'name': 'acme_url', 'type': 'str', 'required': True, 'validation': 'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', 'helpMessage': 'Must be a valid web url starting with http[s]://'}, {'name': 'telephone', 'type': 'str', 'default': '', 'helpMessage': 'Telephone to use'}, {'name': 'email', 'type': 'str', 'default': '', 'validation': '([-!#-\'*+/-9=?A-Z^-~]+(\\.[-!#-\'*+/-9=?A-Z^-~]+)*|\\"([]!#-[^-~ \\t]|(\\\\[\\t -~]))+\\")@([-!#-\'*+/-9=?A-Z^-~]+(\\.[-!#-\'*+/-9=?A-Z^-~]+)*|\\[[\\t -Z^-~]*])', 'helpMessage': 'Email to use'}, {'name': 'certificate', 'type': 'textarea', 'default': '', 'validation': '^-----BEGIN CERTIFICATE-----', 'helpMessage': 'ACME root Certificate'}, {'name': 'store_account', 'type': 'bool', 'required': False, 'helpMessage': 'Disable to create a new account for each ACME request', 'default': False}, {'name': 'eab_kid', 'type': 'str', 'default': '', 'required': False, 'helpMessage': 'Key identifier for the external account.'}, {'name': 'eab_hmac_key', 'type': 'str', 'default': '', 'required': False, 'helpMessage': 'HMAC key for the external account.'}, {'name': 'acme_private_key', 'type': 'textarea', 'default': '', 'required': False, 'helpMessage': 'Account Private Key. Will be encrypted.'}, {'name': 'acme_regr', 'type': 'textarea', 'default': '', 'required': False, 'helpMessage': 'Account Registration'}, {'name': 'tokenDestination', 'type': 'destinationSelect', 'required': True, 'helpMessage': 'The destination to use to deploy the token.'}]
revoke_certificate(certificate, reason)
slug = 'acme-http-issuer'
title = 'Acme HTTP-01'
version = 'unknown'
class lemur.plugins.lemur_acme.plugin.ACMEIssuerPlugin(*args, **kwargs)

Bases: lemur.plugins.bases.issuer.IssuerPlugin

author = 'Netflix'
author_url = 'https://github.com/netflix/lemur.git'
cancel_ordered_certificate(pending_cert, **kwargs)
static create_authority(options)

Creates an authority, this authority is then used by Lemur to allow a user to specify which Certificate Authority they want to sign their certificate.

Parameters

options

Returns

create_certificate(csr, issuer_options)

Creates an ACME certificate using the DNS-01 challenge.

Parameters
  • csr

  • issuer_options

Returns

raise Exception

description = "Enables the creation of certificates via ACME CAs (including Let's Encrypt), using the DNS-01 challenge"
get_ordered_certificate(pending_cert)
get_ordered_certificates(pending_certs)
options = [{'name': 'acme_url', 'type': 'str', 'required': True, 'validation': 'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', 'helpMessage': 'ACME resource URI. Must be a valid web url starting with http[s]://'}, {'name': 'telephone', 'type': 'str', 'default': '', 'helpMessage': 'Telephone to use'}, {'name': 'email', 'type': 'str', 'default': '', 'validation': '([-!#-\'*+/-9=?A-Z^-~]+(\\.[-!#-\'*+/-9=?A-Z^-~]+)*|\\"([]!#-[^-~ \\t]|(\\\\[\\t -~]))+\\")@([-!#-\'*+/-9=?A-Z^-~]+(\\.[-!#-\'*+/-9=?A-Z^-~]+)*|\\[[\\t -Z^-~]*])', 'helpMessage': 'Email to use'}, {'name': 'certificate', 'type': 'textarea', 'default': '', 'validation': '^-----BEGIN CERTIFICATE-----', 'helpMessage': 'ACME root certificate'}, {'name': 'store_account', 'type': 'bool', 'required': False, 'helpMessage': 'Disable to create a new account for each ACME request', 'default': False}, {'name': 'eab_kid', 'type': 'str', 'required': False, 'helpMessage': 'Key identifier for the external account.'}, {'name': 'eab_hmac_key', 'type': 'str', 'required': False, 'helpMessage': 'HMAC key for the external account.'}, {'name': 'acme_private_key', 'type': 'textarea', 'default': '', 'required': False, 'helpMessage': 'Account Private Key. Will be encrypted.'}, {'name': 'acme_regr', 'type': 'textarea', 'default': '', 'required': False, 'helpMessage': 'Account Registration'}]
revoke_certificate(certificate, reason)
slug = 'acme-issuer'
title = 'Acme'
version = 'unknown'

powerdns Module

class lemur.plugins.lemur_acme.powerdns.Record(_data)

Bases: object

This class implements a PowerDNS record.

property content
property disabled
property name
property ttl
property type
class lemur.plugins.lemur_acme.powerdns.Zone(_data)

Bases: object

This class implements a PowerDNS zone in JSON.

property id

Zone id, has a trailing “.” at the end, which we manually remove.

property kind

Indicates whether the zone is setup as a PRIMARY or SECONDARY

property name

Zone name, has a trailing “.” at the end, which we manually remove.

lemur.plugins.lemur_acme.powerdns.create_txt_record(domain, token, account_number)

Create a TXT record for the given domain and token and return a change_id tuple

Parameters
  • domain – FQDN

  • token – challenge value

  • account_number

Returns

tuple of domain/token

lemur.plugins.lemur_acme.powerdns.delete_txt_record(change_id, account_number, domain, token)

Delete the TXT record for the given domain and token

Parameters
  • change_id – tuple of domain/token

  • account_number

  • domain – FQDN

  • token – challenge to delete

Returns

lemur.plugins.lemur_acme.powerdns.get_zones(account_number)

Retrieve authoritative zones from the PowerDNS API and return a list of zones

Parameters

account_number

Raise

Exception

Returns

list of Zone Objects

lemur.plugins.lemur_acme.powerdns.wait_for_dns_change(change_id, account_number=None)

Checks the authoritative DNS Server to see if changes have propagated.

Parameters
  • change_id – tuple of domain/token

  • account_number

Returns

route53 Module

lemur.plugins.lemur_acme.route53.change_txt_record(action, zone_id, domain, value, client=None)
lemur.plugins.lemur_acme.route53.create_txt_record(host, value, account_number)
lemur.plugins.lemur_acme.route53.delete_txt_record(change_ids, account_number, host, value)
lemur.plugins.lemur_acme.route53.find_zone_id(domain, client=None)
lemur.plugins.lemur_acme.route53.get_zones(client=None)
lemur.plugins.lemur_acme.route53.wait_for_dns_change(change_id, client=None)

ultradns Module

class lemur.plugins.lemur_acme.ultradns.Record(_data)

Bases: object

This class implements an Ultra DNS record.

Accepts the response from the API call as the argument.

property name
property rdata
property rrtype
property ttl
class lemur.plugins.lemur_acme.ultradns.Zone(_data, _client='Client')

Bases: object

This class implements an Ultra DNS zone.

property authoritative_type

Indicates whether the zone is setup as a PRIMARY or SECONDARY

property name

Zone name, has a trailing “.” at the end, which we manually remove.

property record_count
property status

Returns the status of the zone - ACTIVE, SUSPENDED, etc

lemur.plugins.lemur_acme.ultradns.create_txt_record(domain, token, account_number)

Create a TXT record for the given domain.

The part of the domain that matches with the zone becomes the zone name. The remainder becomes the owner name (referred to as node name here) Example: Let’s say we have a zone named “exmaple.com” in UltraDNS and we get a request to create a cert for lemur.example.com Domain - _acme-challenge.lemur.example.com Matching zone - example.com Owner name - _acme-challenge.lemur

lemur.plugins.lemur_acme.ultradns.delete_acme_txt_records(domain)
lemur.plugins.lemur_acme.ultradns.delete_txt_record(change_id, account_number, domain, token)

Delete the TXT record that was created in the create_txt_record() function.

UltraDNS handles records differently compared to Dyn. It creates an RRSet which is a set of records of the same type and owner. This means that while deleting the record, we cannot delete any individual record from the RRSet. Instead, we have to delete the entire RRSet. If multiple certs are being created for the same domain at the same time, the challenge TXT records that are created will be added under the same RRSet. If the RRSet had more than 1 record, then we create a new RRSet on UltraDNS minus the record that has to be deleted.

lemur.plugins.lemur_acme.ultradns.get_authoritative_nameserver(domain)

Get the authoritative nameserver for the given domain

lemur.plugins.lemur_acme.ultradns.get_public_authoritative_nameserver()
lemur.plugins.lemur_acme.ultradns.get_ultradns_token()

Function to call the UltraDNS Authorization API.

Returns the Authorization access_token which is valid for 1 hour. Each request calls this function and we generate a new token every time.

lemur.plugins.lemur_acme.ultradns.get_zone_name(domain, account_number)

Get the matching zone for the given domain

lemur.plugins.lemur_acme.ultradns.get_zones(account_number)

Get zones from the UltraDNS

lemur.plugins.lemur_acme.ultradns.wait_for_dns_change(change_id, account_number=None)

Waits and checks if the DNS changes have propagated or not.

First check the domains authoritative server. Once this succeeds, we ask a public DNS server (Google <8.8.8.8> in our case).