After implementing configuration to have a certificate from Let's Encrypt via ACME be requested, then using that certificate for the HTTPS server/API, we noticed the certificate chain is not presented, therefore causing clients to not trust it.
pki { certificate LETS-ENCRYPT { acme { domain-name router.dal1.routedbits.com email <email> } } } service { https { certificates { certificate LETS-ENCRYPT } port 8443 } }
yzguy@prometheus:~# openssl s_client -connect router.dal1.routedbits.com:8443 CONNECTED(00000003) depth=0 CN = router.dal1.routedbits.com verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 CN = router.dal1.routedbits.com verify error:num=21:unable to verify the first certificate verify return:1 depth=0 CN = router.dal1.routedbits.com verify return:1 --- Certificate chain 0 s:CN = router.dal1.routedbits.com i:C = US, O = Let's Encrypt, CN = R3 a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Jan 31 19:03:42 2024 GMT; NotAfter: Apr 30 19:03:41 2024 GMT ---
The ACME support was originally added in https://github.com/vyos/vyos-1x/pull/2758, and looking at the code that was removed it referenced the fullchain.pem
ssl_certificate {{ server.certbot_dir }}/live/{{ server.certbot_domain_dir }}/fullchain.pem;
The new changes later reference only the cert.pem
tmp = read_file(f'{vyos_certbot_dir}/live/{name}/cert.pem')
Poking around, just copying /config/auth/letsencrypt/live/LETS-ENCRYPT/fullchain.pem over cert.pem, then deleting the service https section, adding it back (forcing it to copy the file again just cases it to load the first certificate
Seems perhaps we just need code that loads the chain certificates into PKI CAs, or when it loads the fullchain.pem, it loads all of them instead of just the one
The load_certificate method uses x509.load_pem_x509_certificate which seems to load just one, but there is also load_pem_x509_certificates (would require an upgrade of cryptography to 39.0.0+) that can load multiple, giving you a list of certificates.
This should give you a way to loop over all the certs in the fullchain.pem and load them in just like cert.pem is being loaded now
Something like
from vyos.utils.file import read_file from vyos.pki import load_certificates # new method from vyos.pki import encode_certificate from vyos.pki import is_ca_certificate tmp = read_file(f'{vyos_certbot_dir}/live/{name}/fullchain.pem') tmp = load_certificates(tmp, wrap_tags=False) for cert in tmp: ca_cert_base64s = [] if not is_ca_certificate(cert) cert_base64 = "".join(encode_certificate(tmp).strip().split("\n")[1:-1]) else: ca_cert_base64s.append("".join(encode_certificate(cert).strip().split("\n")[1:-1]))