Skip to content

Commit 875764b

Browse files
committed
pki: T6481: auto import ACME certificate chain into CLI
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.
1 parent 17c9b44 commit 875764b

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

src/conf_mode/pki.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from vyos.configdiff import Diff
2828
from vyos.configdiff import get_config_diff
2929
from vyos.defaults import directories
30+
from vyos.pki import encode_certificate
3031
from vyos.pki import is_ca_certificate
3132
from vyos.pki import load_certificate
3233
from vyos.pki import load_public_key
@@ -36,9 +37,11 @@
3637
from vyos.pki import load_crl
3738
from vyos.pki import load_dh_parameters
3839
from vyos.utils.boot import boot_configuration_complete
40+
from vyos.utils.configfs import add_cli_node
3941
from vyos.utils.dict import dict_search
4042
from vyos.utils.dict import dict_search_args
4143
from vyos.utils.dict import dict_search_recursive
44+
from vyos.utils.file import read_file
4245
from vyos.utils.process import call
4346
from vyos.utils.process import cmd
4447
from vyos.utils.process import is_systemd_service_active
@@ -446,9 +449,37 @@ def generate(pki):
446449
# Get foldernames under vyos_certbot_dir which each represent a certbot cert
447450
if os.path.exists(f'{vyos_certbot_dir}/live'):
448451
for cert in certbot_list_on_disk:
452+
# ACME certificate is no longer in use by CLI remove it
449453
if cert not in certbot_list:
450-
# certificate is no longer active on the CLI - remove it
451454
certbot_delete(cert)
455+
continue
456+
# ACME not enabled for individual certificate - bail out early
457+
if 'acme' not in pki['certificate'][cert]:
458+
continue
459+
460+
# Read in ACME certificate chain information
461+
tmp = read_file(f'{vyos_certbot_dir}/live/{cert}/chain.pem')
462+
tmp = load_certificate(tmp, wrap_tags=False)
463+
cert_chain_base64 = "".join(encode_certificate(tmp).strip().split("\n")[1:-1])
464+
465+
# Check if CA chain certificate is already present on CLI to avoid adding
466+
# a duplicate. This only checks for manual added CA certificates and not
467+
# auto added ones with the AUTOCHAIN_ prefix
468+
autochain_prefix = 'AUTOCHAIN_'
469+
ca_cert_present = False
470+
if 'ca' in pki:
471+
for ca_base64, cli_path in dict_search_recursive(pki['ca'], 'certificate'):
472+
# Ignore automatic added CA certificates
473+
if any(item.startswith(autochain_prefix) for item in cli_path):
474+
continue
475+
if cert_chain_base64 == ca_base64:
476+
ca_cert_present = True
477+
478+
if not ca_cert_present:
479+
tmp = dict_search_args(pki, 'ca', f'{autochain_prefix}{cert}', 'certificate')
480+
if not bool(tmp) or tmp != cert_chain_base64:
481+
print(f'Adding/replacing automatically imported CA certificate for "{cert}" ...')
482+
add_cli_node(['pki', 'ca', f'{autochain_prefix}{cert}', 'certificate'], value=cert_chain_base64)
452483

453484
return None
454485

src/op_mode/pki.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,22 @@
2626

2727
from vyos.config import Config
2828
from vyos.config import config_dict_mangle_acme
29-
from vyos.pki import encode_certificate, encode_public_key, encode_private_key, encode_dh_parameters
29+
from vyos.pki import encode_certificate
30+
from vyos.pki import encode_public_key
31+
from vyos.pki import encode_private_key
32+
from vyos.pki import encode_dh_parameters
3033
from vyos.pki import get_certificate_fingerprint
31-
from vyos.pki import create_certificate, create_certificate_request, create_certificate_revocation_list
34+
from vyos.pki import create_certificate
35+
from vyos.pki import create_certificate_request
36+
from vyos.pki import create_certificate_revocation_list
3237
from vyos.pki import create_private_key
3338
from vyos.pki import create_dh_parameters
34-
from vyos.pki import load_certificate, load_certificate_request, load_private_key
35-
from vyos.pki import load_crl, load_dh_parameters, load_public_key
39+
from vyos.pki import load_certificate
40+
from vyos.pki import load_certificate_request
41+
from vyos.pki import load_private_key
42+
from vyos.pki import load_crl
43+
from vyos.pki import load_dh_parameters
44+
from vyos.pki import load_public_key
3645
from vyos.pki import verify_certificate
3746
from vyos.utils.io import ask_input
3847
from vyos.utils.io import ask_yes_no

0 commit comments

Comments
 (0)