From f5ff8731c641151ec1ee51b99d4cd41ec4e8429d Mon Sep 17 00:00:00 2001 From: selcem Date: Thu, 4 Jan 2024 21:31:16 +0300 Subject: [PATCH] Add crl-distribution-point to upload-signed-csr action New configuration parameter updates URI for CRL Distribution points inside Vault, to a publicly-accessible location. The purpose is not to impact all users, so I did not add a global configuration parameter. Instead, only 'upload_signed_csr' action was updated with an optional parameter introduced named 'crl-distribution-point'. Closes-bug: #2048237 Change-Id: I8dbfc0deb9f547100bb63bd6b20737734e97667b --- src/actions.yaml | 5 ++++ src/actions/actions.py | 3 ++- src/lib/charm/vault_pki.py | 37 +++++++++++++++++--------- unit_tests/test_lib_charm_vault_pki.py | 19 ++++++++++++- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/actions.yaml b/src/actions.yaml index a71ba7f..1ed93ec 100644 --- a/src/actions.yaml +++ b/src/actions.yaml @@ -107,6 +107,11 @@ upload-signed-csr: default: '8760h' description: >- Specifies the maximum Time To Live + crl-distribution-point: + type: string + default: '' + description: >- + Specifies Certificate Revocation List Distribution Point root-ca: type: string description: >- diff --git a/src/actions/actions.py b/src/actions/actions.py index b5a9083..0e038aa 100755 --- a/src/actions/actions.py +++ b/src/actions/actions.py @@ -131,7 +131,8 @@ def upload_signed_csr(*args): allow_subdomains=action_config.get('allow-subdomains'), enforce_hostnames=action_config.get('enforce-hostnames'), allow_any_name=action_config.get('allow-any-name'), - max_ttl=action_config.get('max-ttl')) + max_ttl=action_config.get('max-ttl'), + crl_distribution_point=action_config.get('crl-distribution-point')) set_flag('charm.vault.ca.ready') set_flag('pki.backend.tuned') # reissue any certificates we might previously have provided diff --git a/src/lib/charm/vault_pki.py b/src/lib/charm/vault_pki.py index 49f7fb2..87c454a 100644 --- a/src/lib/charm/vault_pki.py +++ b/src/lib/charm/vault_pki.py @@ -23,7 +23,9 @@ def configure_pki_backend(client, name, ttl=None, max_ttl=None): :param name: Name of backend to enable :type name: str :param ttl: TTL - :type ttl: str + :type ttl: Optional[str] + :param max_ttl: max TTL + :type max_ttl: Optional[str] """ if not vault.is_backend_mounted(client, name): client.sys.enable_secrets_engine( @@ -53,7 +55,9 @@ def tune_pki_backend(ttl=None, max_ttl=None): """Assert tuning options for Charm PKI backend :param ttl: TTL - :type ttl: str + :type ttl: Optional[str] + :param max_ttl: max TTL + :type max_ttl: Optional[str] """ client = vault.get_local_client() if vault.is_backend_mounted(client, CHARM_PKI_MP): @@ -68,6 +72,10 @@ def is_ca_ready(client, name, role): :returns: Whether CA is ready :rtype: bool + :param name: Name of backend to enable + :type name: str + :param role: Name of role + :type role: str """ try: # read_role raises InvalidPath is the role is not available @@ -156,17 +164,17 @@ def get_csr(ttl=None, common_name=None, locality=None, fields embedded in the CSR may have to match the CA. :param ttl: TTL - :type ttl: string + :type ttl: Optional[string] :param country: The C (Country) values in the subject field of the CSR - :type country: string + :type country: Optional[string] :param province: The ST (Province) values in the subject field of the CSR. - :type province: string + :type province: Optional[string] :param organization: The O (Organization) values in the subject field of the CSR - :type organization: string + :type organization: Optional[string] :param organizational_unit: The OU (OrganizationalUnit) values in the subject field of the CSR. - :type organizational_unit: string + :type organizational_unit: Optional[string] :param common_name: The CN (Common_Name) values in the subject field of the CSR. :param locality: The L (Locality) values in the @@ -203,22 +211,24 @@ def get_csr(ttl=None, common_name=None, locality=None, def upload_signed_csr(pem, allowed_domains, allow_subdomains=True, enforce_hostnames=False, allow_any_name=True, - max_ttl=None): + max_ttl=None, crl_distribution_point=None): """Upload signed csr to intermediate pki :param pem: signed csr in pem format :type pem: string :param allow_subdomains: Specifies if clients can request certificates with CNs that are subdomains of the CNs: - :type allow_subdomains: bool + :type allow_subdomains: Optional[bool] :param enforce_hostnames: Specifies if only valid host names are allowed for CNs, DNS SANs, and the host part of email addresses. - :type enforce_hostnames: bool + :type enforce_hostnames: Optional[bool] :param allow_any_name: Specifies if clients can request any CN - :type allow_any_name: bool + :type allow_any_name:Optional[bool] :param max_ttl: Specifies the maximum Time To Live :type max_ttl: str + :param crl_distribution_point: Defines the CRL Distribution Point URI + :type crl_distribution_point: str """ client = vault.get_local_client() # Set the intermediate certificate authorities signing certificate to the @@ -234,7 +244,8 @@ def upload_signed_csr(pem, allowed_domains, allow_subdomains=True, { "issuing_certificates": "{}/v1/{}/ca".format(addr, CHARM_PKI_MP), "crl_distribution_points": - "{}/v1/{}/crl".format(addr, CHARM_PKI_MP), + ("{}/v1/{}/crl".format(addr, CHARM_PKI_MP) if not crl_distribution_point + else crl_distribution_point), }, mount_point=CHARM_PKI_MP ) @@ -388,7 +399,7 @@ def is_cert_from_vault(cert, name=None): :param cert: the certificate in x509 form :type cert: str :param name: the mount point in value, default CHARM_PKI_MP - :type name: str + :type name: Optional[str] :returns: True if issued by vault, False if unknown. :raises VaultDown: if vault is down. :raises VaultNotReady: if vault is sealed. diff --git a/unit_tests/test_lib_charm_vault_pki.py b/unit_tests/test_lib_charm_vault_pki.py index f1c2bfb..ea0a905 100644 --- a/unit_tests/test_lib_charm_vault_pki.py +++ b/unit_tests/test_lib_charm_vault_pki.py @@ -260,6 +260,23 @@ class TestLibCharmVaultPKI(unit_tests.test_utils.CharmTestCase): 'MYPEM', mount_point=vault_pki.CHARM_PKI_MP ) + @patch.object(vault_pki.vault, 'get_access_address') + @patch.object(vault_pki.vault, 'get_local_client') + def test_upload_signed_csr_cdp(self, get_local_client, get_access_address): + get_access_address.return_value = 'https://vault.local:8200' + client_mock = mock.MagicMock() + get_local_client.return_value = client_mock + local_url = 'https://vault.local:8200/v1/charm-pki-local' + vault_pki.upload_signed_csr( + 'MYPEM', 'example.com', crl_dist_point='https://test-cdp.com' + ) + client_mock.secrets.pki.set_urls.assert_called_once_with( + { + 'issuing_certificates': '{}/ca'.format(local_url), + 'crl_distribution_points': 'https://test-cdp.com', + }, mount_point=vault_pki.CHARM_PKI_MP + ) + @patch.object(vault_pki.vault, 'get_access_address') @patch.object(vault_pki.vault, 'get_local_client') def test_upload_signed_csr_ipv4( @@ -335,7 +352,7 @@ class TestLibCharmVaultPKI(unit_tests.test_utils.CharmTestCase): allow_subdomains=False, enforce_hostnames=True, allow_any_name=False, - max_ttl='42h') + max_ttl='42h', crl_dist_point=None) client_mock.secrets.pki.set_signed_intermediate.\ assert_called_once_with( 'MYPEM', mount_point='charm-pki-local'