Skip to content

Commit

Permalink
pki: T6481: auto import ACME certificate chain into CLI
Browse files Browse the repository at this point in the history
When using an ACME based certificate with VyOS we provide the necessary PEM
files opaque in the background when using the internal tools. This however will
not properly work with the CA chain portion, as the system is based on the
"pki certificate <name> acme" CLI node of a certificate but CA chains reside
under "pki ca".

This adds support for importing the PEM data of a CA chain issued via ACME into
the "pki ca AUTOCHAIN_<name> certificate" subsystem so it can be queried by
other daemons. Importing the chain only happens, when the chain was not already
added manually by the user.

ACME certificate chains that are automatically added to the CLI are all prefixed
using AUTOCHAIN_certname so they can be consumed by any daemon. This also adds
a safeguard when the intermediate CA changes, the referenced name on the CLI
stays consitent for any pending daemon updates.
  • Loading branch information
c-po committed Oct 6, 2024
1 parent 17c9b44 commit 875764b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
33 changes: 32 additions & 1 deletion src/conf_mode/pki.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from vyos.configdiff import Diff
from vyos.configdiff import get_config_diff
from vyos.defaults import directories
from vyos.pki import encode_certificate
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
from vyos.pki import load_public_key
Expand All @@ -36,9 +37,11 @@
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
from vyos.utils.boot import boot_configuration_complete
from vyos.utils.configfs import add_cli_node
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
from vyos.utils.file import read_file
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import is_systemd_service_active
Expand Down Expand Up @@ -446,9 +449,37 @@ def generate(pki):
# Get foldernames under vyos_certbot_dir which each represent a certbot cert
if os.path.exists(f'{vyos_certbot_dir}/live'):
for cert in certbot_list_on_disk:
# ACME certificate is no longer in use by CLI remove it
if cert not in certbot_list:
# certificate is no longer active on the CLI - remove it
certbot_delete(cert)
continue
# ACME not enabled for individual certificate - bail out early
if 'acme' not in pki['certificate'][cert]:
continue

# Read in ACME certificate chain information
tmp = read_file(f'{vyos_certbot_dir}/live/{cert}/chain.pem')
tmp = load_certificate(tmp, wrap_tags=False)
cert_chain_base64 = "".join(encode_certificate(tmp).strip().split("\n")[1:-1])

# Check if CA chain certificate is already present on CLI to avoid adding
# a duplicate. This only checks for manual added CA certificates and not
# auto added ones with the AUTOCHAIN_ prefix
autochain_prefix = 'AUTOCHAIN_'
ca_cert_present = False
if 'ca' in pki:
for ca_base64, cli_path in dict_search_recursive(pki['ca'], 'certificate'):
# Ignore automatic added CA certificates
if any(item.startswith(autochain_prefix) for item in cli_path):
continue
if cert_chain_base64 == ca_base64:
ca_cert_present = True

if not ca_cert_present:
tmp = dict_search_args(pki, 'ca', f'{autochain_prefix}{cert}', 'certificate')
if not bool(tmp) or tmp != cert_chain_base64:
print(f'Adding/replacing automatically imported CA certificate for "{cert}" ...')
add_cli_node(['pki', 'ca', f'{autochain_prefix}{cert}', 'certificate'], value=cert_chain_base64)

return None

Expand Down
17 changes: 13 additions & 4 deletions src/op_mode/pki.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@

from vyos.config import Config
from vyos.config import config_dict_mangle_acme
from vyos.pki import encode_certificate, encode_public_key, encode_private_key, encode_dh_parameters
from vyos.pki import encode_certificate
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
from vyos.pki import encode_dh_parameters
from vyos.pki import get_certificate_fingerprint
from vyos.pki import create_certificate, create_certificate_request, create_certificate_revocation_list
from vyos.pki import create_certificate
from vyos.pki import create_certificate_request
from vyos.pki import create_certificate_revocation_list
from vyos.pki import create_private_key
from vyos.pki import create_dh_parameters
from vyos.pki import load_certificate, load_certificate_request, load_private_key
from vyos.pki import load_crl, load_dh_parameters, load_public_key
from vyos.pki import load_certificate
from vyos.pki import load_certificate_request
from vyos.pki import load_private_key
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
from vyos.pki import load_public_key
from vyos.pki import verify_certificate
from vyos.utils.io import ask_input
from vyos.utils.io import ask_yes_no
Expand Down

0 comments on commit 875764b

Please sign in to comment.