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 <name> certificate" subsystem so it can be queried by other
daemons.

NOTE: The intermediate CA used by e.g. LetsEncrypt might change during the
lifecycle of a certificate. Many of you might remember the R3 intermediate CA,
which now became the R10 intermediate CA.
  • Loading branch information
c-po committed Oct 1, 2024
1 parent 2ba5089 commit 9d31532
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
32 changes: 31 additions & 1 deletion src/conf_mode/pki.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import re
import os

from sys import argv
Expand All @@ -27,6 +28,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 +38,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 +450,35 @@ 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])

# Remove non alpha-numeric, hypen and underscore characters
# and limit string to 32 characters - used for dynamic generated CLI node
allower_characters = '[^a-zA-Z0-9_-]'
subject = re.sub(allower_characters, '', tmp.subject.rfc4514_string())[:32]

# Check if CA chain certificate is already installed in CLI to avoid adding
# a duplicate. This works for both manual added CA certificates and automatic
# added ones via ACME.
ca_cert_present = False
if 'ca' in pki:
for ca_base64, _ in dict_search_recursive(pki['ca'], 'certificate'):
if cert_chain_base64 == ca_base64:
ca_cert_present = True

if not ca_cert_present and ('ca' not in pki or subject not in pki['ca']):
add_cli_node(['pki', 'ca', subject, '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 9d31532

Please sign in to comment.