HashiCorp Vault setup - Kubernetes and cert-manager
Configure HashiCorp Vault and the certificate manager in Kubernetes to use the DigiCert PKI secrets engine, instead of the Vault internal secrets engine. X.509 certificates are dynamically generated within Kubernetes through an Issuer interface.
Before you begin
Prerequisites
Active, self-hosted Vault instance
Important
DigiCert® Trust Lifecycle Manager. does not support cloud-hosted instances of Vault.
Docker
Helm CLI
Kubernetes CLI
Minikube
cert-manager
DigiCert®Vault PKI plugin binary for the required OS and chipset
Integration workflow
Get the plug-in from DigiCert® Trust Lifecycle Manager:
Sign in to DigiCert® Trust Lifecycle Manager.
Go to Integrations > Connectors.
In the Vaults section, choose HashiCorp.
Follow the steps to download the plugin binary.
Move the plugin to the
plugin_directory
defined in the next procedure.
Install Vault using its Helm chart and unseal the vault for use. Refer to the HashiCorp documentation for detailed assistance.
Copy the HashiCorp Vault plugin into the
vault-0
pod and configure theplugin_directory
path in the Vault configuration file.Start an interactive shell session on the
vault-0
pod.$ kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh
Register the plugin in Vault.
vault write sys/plugins/catalog/secret/vault-pki-backend-digicert sha_256="a2b10f2b8c3e76ec2580651fdb3bd012a11eafc20e2f62020956282df16b9a9e" command="vault-pki-backend-digicert"
Enable the DigiCert® PKI secrets engine.
vault secrets enable -path=digicert-pki -plugin-name=vault-pki-backend-digicert plugin
Create a configuration that allows the plugin to connect with the DigiCert® environment.
vault write digicert-pki/configs/stage-dcone url="https://stage.one.digicert.com/" api_key="01aad362f1610f7d9e171f0fa2_80995e78c63a8e7d474c41dbecb2a165f049aa47799ad42f90fc386b1edb680c"
Response:
Success! Data written to: digicert-pki/configs/stage-dcone
Create a role to define the default
profile_id
.Notice
The
profile_id
defined for role is the default and can be overridden by passing a different ID with the certificate request.vault write digicert-pki/roles/stage config_name="stage-dcone" profile_id="017e05b0-fedc-4a9a-88f7-1fd759f20f37"
Response:
Success! Data written to: digicert-pki/roles/stage
Create a policy called
digicert-pki
that enables read access to the PKI secrets engine paths.vault policy write digicert-pki path "digicert-pki*" { capabilities = ["read", "list"] } path "digicert-pki/sign/win-the-customer-com" { capabilities = ["create", "update"] } path "digicert-pki/issue/win-the-customer-com" { capabilities = ["create"] }
Refer to the HashiCorp documentation for detailed assistance with these steps.
Configure Vault to enable clients to authenticate with a Kubernetes Service Account token. Create an authentication role named
issuer
in thevault-0
pod and bind it to thedigicert-pki
policy with the Kubernetes Service Account.vault write auth/kubernetes/role/issuer \ bound_service_account_names=issuer \ bound_service_account_namespaces=default \ policies=digicert-pki \ ttl=20m
Deploy cert-manager.
The cert-manager allows you to define Issuers that interact with the Vault endpoints for generating certificates. These Issuers are invoked when a certificate is requested.
Create a Service Account called
issuer
in the default namespace.$ kubectl create serviceaccount issuer
To set up a Vault issuer you must first create a Kubernetes Secret resource. The Service Account generates a secret that is required by the Issuer in Kubernetes 1.23. In Kubernetes 1.24+, you need to explicitly create the secret.
$ cat >> issuer-secret.yaml apiVersion: v1 kind: Secret metadata: name: issuer-token-lmzpj annotations: kubernetes.io/service-account.name: issuer type: kubernetes.io/service-account-token
Create an issuer secret.
$ kubectl apply -f issuer-secret.yaml secret/issuer-token-lmzpj created
Get all the secrets in the default namespace. The issuer secret is shown here prefixed with
issuer-token
.$ kubectl get secrets NAME TYPE DATA AGE issuer-token-lmzpj kubernetes.io/service-account-token 3 6s sh.helm.release.v1.vault.v1 helm.sh/release.v1 1 33m
Create a variable named
ISSUER_SECRET_REF
to capture the secret name.ISSUER_SECRET_REF=$(kubectl get secrets --output=json | jq -r '.items[].metadata | select(.name|startswith("issuer-token-")).name')
Define an Issuer resource called
vault-issuer
, which sets Vault as a certificate issuer.$ cat > vault-issuer.yaml apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: vault-issuer namespace: default spec: vault: server: http://vault.default:8200 path: digicert-pki/sign/win-the-customer-com auth: kubernetes: mountPath: /v1/auth/kubernetes role: issuer secretRef: name: $ISSUER_SECRET_REF key: token
Create the
vault-issuer
Issuer.$ kubectl apply --filename vault-issuer.yaml
Key | Description |
---|---|
metadata.name | Set the name of the Issuer to |
spec.vault.server | Set the server address to the Kubernetes service created in the default namespace. |
spec.vault.path | Set the signing endpoint for the Vault role ( |
spec.vault.auth.kubernetes.mountPath | Set the Vault authentication endpoint. |
spec.vault.auth.kubernetes.role | Set the Vault Kubernetes role to |
spec.vault.auth.kubernetes/secretRef.name | Set the secret for the Kubernetes Service Account. |
spec.vault.auth.kubernetes/secretRef.key | Set key type to |
Define a certificate named
win-the-customer-com
(for example).cat > win-the-customer-com-cert.yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: win-the-customer-com namespace: default spec: secretName: win-the-customer-com-tls issuerRef: name: vault-issuer commonName: test.winthecustomer1.com dnsNames: - test.winthecustomer1.com
Request the
win-the-customer-com
certificate.kubectl apply --filename win-the-customer-com.yaml
View the details of the certificate.
Common Name: test29sept.winthecustomer.com Dns Names: test27septdns.winthecustomer.com Issuer Ref: Name: issuer Secret Name: win-the-customer-com-tls Status: Conditions: Last Transition Time: 2024-09-29T18:08:37Z Message: Certificate is up to date and has not expired Observed Generation: 1 Reason: Ready Status: True Type: Ready Not After: 2024-10-29T18:08:37Z Not Before: 2024-09-29T18:08:37Z Renewal Time: 2024-10-19T18:08:37Z Revision: 1 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 28s cert-manager-certificates-trigger Issuing certificate as Secret does not exist Normal Generated 28s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "win-the-customer-com-q22vp" Normal Requested 28s cert-manager-certificates-request-manager Created new CertificateRequest resource "win-the-customer-com-z9lhx" Normal Issuing 26s cert-manager-certificates-issuing The certificate has been successfully issued
The certificate issued from DigiCert is now added to your Kubernetes secrets and a copy will also be stored in the
vault-0
directory.vault list vault-pki/certs Keys ---- 281b93ecc49106db473084f5e41095034f67a0a0 56195e18913c66d277b2e509c8b0e194925f59f9 6937bbf0ba698f270804a954c02139507fc25998 7a8619ed9ae90f04dd7a2180887b35bfb487cc81
What's next
After Vault is successfully configured, refer to configuration and certificate operations for all other activities.