acertmgr: store CSR and support static CSR usage

Store the generated CSR for later review/usage and allow the stored
CSR to be used for future request. Configuration directives csr_file
(path) and csr_static (=true) have been added for this.

This allows simplified deployment of DANE/TLSA due the former requiring
updates to DNS with every public key change, which will not be the case
with a static CSR. A new CSR can be triggered manually by deleting the
CSR file upon which the next certificate will require an update of any
TLSA records in DNS.

This may also be used to specify a custom CSR to use, as long as the
csr_file path and the domains in the CSR match the ones given in the
acertmgr configuration.
This commit is contained in:
Kishi85 2019-03-24 17:22:04 +01:00
parent 5171a93608
commit ed96f2bbf2
3 changed files with 19 additions and 2 deletions

View File

@ -70,7 +70,14 @@ def cert_get(settings):
key = tools.new_ssl_key(key_file, key_length)
# create ssl csr
cr = tools.new_cert_request(settings['domainlist'], key)
csr_file = settings['csr_file']
if os.path.isfile(csr_file) and str(settings['csr_static']).lower() == 'true':
print('Loading CSR from {}'.format(csr_file))
cr = tools.read_pem_file(csr_file, csr=True)
else:
print('Generating CSR for {}'.format(settings['domainlist']))
cr = tools.new_cert_request(settings['domainlist'], key)
tools.write_pem_file(cr, csr_file)
# request cert with csr
crt, ca = acme.get_crt_from_csr(cr, settings['domainlist'], challenge_handlers)

View File

@ -113,6 +113,13 @@ def parse_config_entry(entry, globalconfig, work_dir, authority_tos_agreement):
update_config_value(config, 'ttl_days', entry, globalconfig, DEFAULT_TTL)
config['ttl_days'] = int(config['ttl_days'])
# Use a static cert request
update_config_value(config, 'csr_static', entry, globalconfig, "false")
# SSL cert request location
update_config_value(config, 'csr_file', entry, globalconfig,
os.path.join(config['cert_dir'], "{}.csr".format(config['id'])))
# SSL cert location (with compatibility to older versions)
if 'server_cert' in globalconfig:
print("WARNING: Legacy configuration directive 'server_cert' used. Support will be removed in 1.0")

View File

@ -102,11 +102,14 @@ def new_ssl_key(path=None, key_size=4096):
# @brief read a key from file
# @param path path to file
# @param key indicate whether we are loading a key
# @param csr indicate whether we are loading a csr
# @return the key in pyopenssl format
def read_pem_file(path, key=False):
def read_pem_file(path, key=False, csr=False):
with io.open(path, 'r') as f:
if key:
return serialization.load_pem_private_key(f.read().encode('utf-8'), None, default_backend())
elif csr:
return x509.load_pem_x509_csr(f.read().encode('utf8'), default_backend())
else:
return convert_pem_str_to_cert(f.read())