»Standalone Server with TLS

This example can be used to set up a single server Vault cluster using TLS.

  1. Create key & certificate using Kubernetes CA
  2. Store key & cert into Kubernetes secrets store
  3. Configure helm chart to use Kubernetes secret from step 2

»1. Create key & certificate using Kubernetes CA

There are four variables that will be used in this example.

# SERVICE is the name of the Vault service in Kubernetes.
# It does not have to match the actual running service, though it may help for consistency.
export SERVICE=vault-server-tls

# NAMESPACE where the Vault service is running.
export NAMESPACE=vault-namespace

# SECRET_NAME to create in the Kubernetes secrets store.
export SECRET_NAME=vault-server-tls

# TMPDIR is a temporary working directory.
export TMPDIR=/tmp

# CSR_NAME will be the name of our certificate signing request as seen by Kubernetes.
export CSR_NAME=vault-csr
# SERVICE is the name of the Vault service in Kubernetes.# It does not have to match the actual running service, though it may help for consistency.export SERVICE=vault-server-tls
# NAMESPACE where the Vault service is running.export NAMESPACE=vault-namespace
# SECRET_NAME to create in the Kubernetes secrets store.export SECRET_NAME=vault-server-tls
# TMPDIR is a temporary working directory.export TMPDIR=/tmp
# CSR_NAME will be the name of our certificate signing request as seen by Kubernetes.export CSR_NAME=vault-csr
  1. Create a key for Kubernetes to sign.

    $ openssl genrsa -out ${TMPDIR}/vault.key 2048
    Generating RSA private key, 2048 bit long modulus
    ...................................................................................................+++
    ...............+++
    e is 65537 (0x10001)
    
    $ openssl genrsa -out ${TMPDIR}/vault.key 2048Generating RSA private key, 2048 bit long modulus...................................................................................................+++...............+++e is 65537 (0x10001)
  2. Create a Certificate Signing Request (CSR).

    1. Create a file ${TMPDIR}/csr.conf with the following contents:

      cat <<EOF >${TMPDIR}/csr.conf
      [req]
      req_extensions = v3_req
      distinguished_name = req_distinguished_name
      [req_distinguished_name]
      [ v3_req ]
      basicConstraints = CA:FALSE
      keyUsage = nonRepudiation, digitalSignature, keyEncipherment
      extendedKeyUsage = serverAuth
      subjectAltName = @alt_names
      [alt_names]
      DNS.1 = ${SERVICE}
      DNS.2 = ${SERVICE}.${NAMESPACE}
      DNS.3 = ${SERVICE}.${NAMESPACE}.svc
      DNS.4 = ${SERVICE}.${NAMESPACE}.svc.cluster.local
      IP.1 = 127.0.0.1
      EOF
      
      cat <<EOF >${TMPDIR}/csr.conf[req]req_extensions = v3_reqdistinguished_name = req_distinguished_name[req_distinguished_name][ v3_req ]basicConstraints = CA:FALSEkeyUsage = nonRepudiation, digitalSignature, keyEnciphermentextendedKeyUsage = serverAuthsubjectAltName = @alt_names[alt_names]DNS.1 = ${SERVICE}DNS.2 = ${SERVICE}.${NAMESPACE}DNS.3 = ${SERVICE}.${NAMESPACE}.svcDNS.4 = ${SERVICE}.${NAMESPACE}.svc.cluster.localIP.1 = 127.0.0.1EOF
    2. Create a CSR.

      $ openssl req -new -key ${TMPDIR}/vault.key \
          -subj "/O=system:nodes/CN=system:node:${SERVICE}.${NAMESPACE}.svc" \
          -out ${TMPDIR}/server.csr \
          -config ${TMPDIR}/csr.conf
      
      $ openssl req -new -key ${TMPDIR}/vault.key \    -subj "/O=system:nodes/CN=system:node:${SERVICE}.${NAMESPACE}.svc" \    -out ${TMPDIR}/server.csr \    -config ${TMPDIR}/csr.conf
  3. Create the certificate

    1. Create a file ${TMPDIR}/csr.yaml with the following contents:

      cat <<EOF >${TMPDIR}/csr.yaml
      apiVersion: certificates.k8s.io/v1
      kind: CertificateSigningRequest
      metadata:
        name: ${CSR_NAME}
      spec:
        groups:
        - system:authenticated
        request: $(cat ${TMPDIR}/server.csr | base64 | tr -d '\r\n')
        signerName: kubernetes.io/kubelet-serving
        usages:
        - digital signature
        - key encipherment
        - server auth
      EOF
      
      cat <<EOF >${TMPDIR}/csr.yamlapiVersion: certificates.k8s.io/v1kind: CertificateSigningRequestmetadata:  name: ${CSR_NAME}spec:  groups:  - system:authenticated  request: $(cat ${TMPDIR}/server.csr | base64 | tr -d '\r\n')  signerName: kubernetes.io/kubelet-serving  usages:  - digital signature  - key encipherment  - server authEOF
    2. Send the CSR to Kubernetes.

      $ kubectl create -f ${TMPDIR}/csr.yaml
      certificatesigningrequest.certificates.k8s.io/vault-csr created
      
      $ kubectl create -f ${TMPDIR}/csr.yamlcertificatesigningrequest.certificates.k8s.io/vault-csr created
    3. Approve the CSR in Kubernetes.

      $ kubectl certificate approve ${CSR_NAME}
      certificatesigningrequest.certificates.k8s.io/vault-csr approved
      
      $ kubectl certificate approve ${CSR_NAME}certificatesigningrequest.certificates.k8s.io/vault-csr approved
    4. Verify that the certificate was approved and issued.

      $ kubectl get csr ${CSR_NAME}
      NAME        AGE     SIGNERNAME                                    REQUESTOR                        CONDITION
      vault-csr   1m13s   kubernetes.io/kubelet-serving                 kubernetes-admin                 Approved,Issued
      
      $ kubectl get csr ${CSR_NAME}NAME        AGE     SIGNERNAME                                    REQUESTOR                        CONDITIONvault-csr   1m13s   kubernetes.io/kubelet-serving                 kubernetes-admin                 Approved,Issued

»2. Store key, cert, and Kubernetes CA into Kubernetes secrets store

  1. Retrieve the certificate.

    $ serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')
    
    $ serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')
  2. Write the certificate out to a file.

    $ echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt
    
    $ echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt
  3. Retrieve Kubernetes CA.

    $ kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ${TMPDIR}/vault.ca
    
    $ kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}' | base64 -d > ${TMPDIR}/vault.ca
  4. Create the namespace.

    $ kubectl create namespace ${NAMESPACE}
    namespace/vault-namespace created
    
    $ kubectl create namespace ${NAMESPACE}namespace/vault-namespace created
  5. Store the key, cert, and Kubernetes CA into Kubernetes secrets.

    $ kubectl create secret generic ${SECRET_NAME} \
        --namespace ${NAMESPACE} \
        --from-file=vault.key=${TMPDIR}/vault.key \
        --from-file=vault.crt=${TMPDIR}/vault.crt \
        --from-file=vault.ca=${TMPDIR}/vault.ca
    
    # secret/vault-server-tls created
    
    $ kubectl create secret generic ${SECRET_NAME} \    --namespace ${NAMESPACE} \    --from-file=vault.key=${TMPDIR}/vault.key \    --from-file=vault.crt=${TMPDIR}/vault.crt \    --from-file=vault.ca=${TMPDIR}/vault.ca
    # secret/vault-server-tls created

»3. Helm Configuration

The below custom-values.yaml can be used to set up a single server Vault cluster using TLS. This assumes that a Kubernetes secret exists with the server certificate, key and certificate authority:

global:
  enabled: true
  tlsDisable: false

server:
  extraEnvironmentVars:
    VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca

  extraVolumes:
    - type: secret
      name: vault-server-tls # Matches the ${SECRET_NAME} from above

  standalone:
    enabled: true
    config: |
      listener "tcp" {
        address = "[::]:8200"
        cluster_address = "[::]:8201"
        tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"
        tls_key_file  = "/vault/userconfig/vault-server-tls/vault.key"
        tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca"
      }

      storage "file" {
        path = "/vault/data"
      }
global:  enabled: true  tlsDisable: false
server:  extraEnvironmentVars:    VAULT_CACERT: /vault/userconfig/vault-server-tls/vault.ca
  extraVolumes:    - type: secret      name: vault-server-tls # Matches the ${SECRET_NAME} from above
  standalone:    enabled: true    config: |      listener "tcp" {        address = "[::]:8200"        cluster_address = "[::]:8201"        tls_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"        tls_key_file  = "/vault/userconfig/vault-server-tls/vault.key"        tls_client_ca_file = "/vault/userconfig/vault-server-tls/vault.ca"      }
      storage "file" {        path = "/vault/data"      }