Skip to main content

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:

  1. Sign in to DigiCert​​®​​ Trust Lifecycle Manager.

  2. Go to Integrations > Connectors.

  3. In the Vaults section, choose HashiCorp.

  4. Follow the steps to download the plugin binary.

  5. Move the plugin to the plugin_directory defined in the next procedure.

  1. Install Vault using its Helm chart and unseal the vault for use. Refer to the HashiCorp documentation for detailed assistance.

  2. Copy the HashiCorp Vault plugin into the vault-0 pod and configure the plugin_directory path in the Vault configuration file.

  3. Start an interactive shell session on the vault-0 pod.

    $ kubectl exec --stdin=true --tty=true vault-0 -- /bin/sh
  4. Register the plugin in Vault.

    vault write sys/plugins/catalog/secret/vault-pki-backend-digicert 
    sha_256="a2b10f2b8c3e76ec2580651fdb3bd012a11eafc20e2f62020956282df16b9a9e" 
    command="vault-pki-backend-digicert"
  5. Enable the DigiCert​​®​​ PKI secrets engine.

    vault secrets enable -path=digicert-pki -plugin-name=vault-pki-backend-digicert plugin
  6. 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
  7. 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
  8. 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.

  1. Configure Vault to enable clients to authenticate with a Kubernetes Service Account token. Create an authentication role named issuer in the vault-0 pod and bind it to the digicert-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
  2. 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.

  1. Create a Service Account called issuer in the default namespace.

    $ kubectl create serviceaccount issuer
  2. 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
    
  3. Create an issuer secret.

    $ kubectl apply -f issuer-secret.yaml
    secret/issuer-token-lmzpj created
  4. 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
  5. 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')
  6. 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
    
  7. Create the vault-issuer Issuer.

    $ kubectl apply --filename vault-issuer.yaml

Key

Description

metadata.name

Set the name of the Issuer to vault-issuer.

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 (win-the-customer-com in this example).

spec.vault.auth.kubernetes.mountPath

Set the Vault authentication endpoint.

spec.vault.auth.kubernetes.role

Set the Vault Kubernetes role to issuer.

spec.vault.auth.kubernetes/secretRef.name

Set the secret for the Kubernetes Service Account.

spec.vault.auth.kubernetes/secretRef.key

Set key type to token.

  1. 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
    
  2. Request the win-the-customer-com certificate.

    kubectl apply --filename win-the-customer-com.yaml
    
  3. 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
  4. 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.