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
This commit is contained in:
selcem 2024-01-04 21:31:16 +03:00
parent e00cb3f3f4
commit 1ef46b87c6
5 changed files with 65 additions and 19 deletions

View File

@ -31,7 +31,7 @@ The `channel` option sets the snap channel to use for deployment (e.g.
> 'Post-deployment tasks' covers this.
Vault is often containerised. Here a single unit is deployed to a new
container on machine '1':
container on existing machine '1':
juju deploy --to lxd:1 vault
@ -190,7 +190,7 @@ Sample output:
This temporary token ('token') is then used to authorise the charm:
juju run-action --wait vault/leader authorize-charm token=s.QMhaOED3UGQ4MeH3fmGOpNED
juju run --wait=0s vault/leader authorize-charm token=s.QMhaOED3UGQ4MeH3fmGOpNED
After the action completes execution, the vault unit(s) will become active and
any pending requests for secrets storage will be processed for consuming
@ -232,7 +232,16 @@ Actions allow specific operations to be performed on a per-unit basis.
* `restart`
To display action descriptions run `juju actions --schema vault`. If the charm
is not deployed then see file `actions.yaml`.
is not deployed then see file `actions.yaml`. Here is a sample command:
## Post-deployment Configuration
To update Certificate Revocation Lists (CRL) Distribution Point URI inside Vault
CA, a configuration option exists in upload-signed-csr action. It could be set
to a publicly accessible URI.
juju run --wait=0s vault/leader upload-signed-csr pem=<> root-ca=<> \
crl-distribution-point=<>
## High availability

View File

@ -107,6 +107,14 @@ upload-signed-csr:
default: '8760h'
description: >-
Specifies the maximum Time To Live
crl-distribution-point:
type: string
default: ''
description: >-
Provide an alternative URL for the Certificate Revocation List (CRL) distribution point that is included
in all certificates issued by Vault. This relies on an external process to synchronise certificates
revoked in Vault to this external distribution point and should only be used when the Vault infrastructure is not
generally accessible to client endpoints used to access services secured by the Vault Intermediate CA.
root-ca:
type: string
description: >-

View File

@ -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

View File

@ -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
:type max_ttl: Optional[str]
:param crl_distribution_point: Defines the CRL Distribution Point URI
:type crl_distribution_point: Optional[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.

View File

@ -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_distribution_point='https://cdp.com'
)
client_mock.secrets.pki.set_urls.assert_called_once_with(
{
'issuing_certificates': '{}/ca'.format(local_url),
'crl_distribution_points': 'https://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_distribution_point=None)
client_mock.secrets.pki.set_signed_intermediate.\
assert_called_once_with(
'MYPEM', mount_point='charm-pki-local'