---
layout: 'docs'
page_title: 'Standalone Server with TLS'
sidebar_current: 'docs-platform-k8s-examples-standalone-tls'
description: |-
  Describes how to set up a standalone Vault with TLS certificate
---

# Standalone server with TLS

@include 'helm/version.mdx'

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](https://kubernetes.io/docs/concepts/configuration/secret/)
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.

```bash
# 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.

   ```shell-session
   $ openssl genrsa -out ${TMPDIR}/vault.key 2048
   Generating 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:

      ```bash
      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
      ```

   2. Create a CSR.

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

3. Create the certificate

   ~> **Important Note:** If you are using EKS, certificate signing requirements have changed.  As per the AWS [certificate signing](https://docs.aws.amazon.com/eks/latest/userguide/cert-signing.html) documentation, EKS version `1.22` and later now requires the `signerName` to be `beta.eks.amazonaws.com/app-serving`, otherwise, the CSR will be approved but the certificate will not be issued.

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

      ```bash
      cat <<EOF >${TMPDIR}/csr.yaml
      apiVersion: certificates.k8s.io/v1
      kind: CertificateSigningRequest
      metadata:
        name: ${CSR_NAME}
      spec:
        signerName: kubernetes.io/kubelet-serving
        groups:
        - system:authenticated
        request: $(base64 ${TMPDIR}/server.csr | tr -d '\n')
        signerName: kubernetes.io/kubelet-serving
        usages:
        - digital signature
        - key encipherment
        - server auth
      EOF
      ```

   2. Send the CSR to Kubernetes.

      ```shell-session
      $ kubectl create -f ${TMPDIR}/csr.yaml
      certificatesigningrequest.certificates.k8s.io/vault-csr created
      ```

      -> If this process is automated, you may need to wait to ensure the CSR has been received and stored:
      `kubectl get csr ${CSR_NAME}`

   3. Approve the CSR in Kubernetes.

      ```shell-session
      $ kubectl certificate approve ${CSR_NAME}
      certificatesigningrequest.certificates.k8s.io/vault-csr approved
      ```

   4. Verify that the certificate was approved and issued.
      ```shell-session
      $ kubectl get csr ${CSR_NAME}
      NAME        AGE     SIGNERNAME                                    REQUESTOR                        CONDITION
      vault-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.

   ```shell-session
   $ serverCert=$(kubectl get csr ${CSR_NAME} -o jsonpath='{.status.certificate}')
   ```

   -> If this process is automated, you may need to wait to ensure the certificate has been created.
   If it hasn't, this will return an empty string.

2. Write the certificate out to a file.

   ```shell-session
   $ echo "${serverCert}" | openssl base64 -d -A -out ${TMPDIR}/vault.crt
   ```

3. Retrieve Kubernetes CA.

   ```bash
   kubectl get secret \
     -o jsonpath="{.items[?(@.type==\"kubernetes.io/service-account-token\")].data['ca\.crt']}" \
     | base64 --decode > ${TMPDIR}/vault.ca
   ```

4. Create the namespace.

    ```shell-session
    $ kubectl create namespace ${NAMESPACE}
    namespace/vault-namespace created
    ```

5. Store the key, cert, and Kubernetes CA into Kubernetes secrets.

   ```shell-session
   $ 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:

```yaml
global:
  enabled: true
  tlsDisable: false

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

  volumes:
    - name: userconfig-vault-server-tls
      secret:
        defaultMode: 420
        secretName: vault-server-tls # Matches the ${SECRET_NAME} from above

  volumeMounts:
    - mountPath: /vault/userconfig/vault-server-tls
      name: userconfig-vault-server-tls
      readOnly: true

  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"
      }
```
