Table of Contents

Vault

Configure TLS

Create a TLS secret used by Vault and Traefik to communicate with vault service

export CERT_DIR=cert
export SECRET_NAME=vault-server-tls

Generate certificate via Kubernetes CertificateSigningRequest

Generate key:

openssl genrsa -out ${CERT_DIR}/vault.key 4096

Generate server.csr:

openssl req -config ${CERT_DIR}/csr.conf -new -key ${CERT_DIR}/vault.key -subj "/CN=vault.vault.svc" -out ${CERT_DIR}/server.csr

Generate CertificateSigningRequest Create ${CERT_DIR}/csr.yaml

download
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: vault-csr
spec:
  groups:
  - system:authenticated
  request: $(cat ${CERT_DIR}/server.csr | base64 | tr -d '\n')
  signerName: beta.eks.amazonaws.com/app-serving
  usages:
  - digital signature
  - key encipherment
  - server auth

Apply CertificateSigningRequest & approve:

kubectl create -f ${CERT_DIR}/csr.yaml
# Approve the Self-Signed Certificate by K8S CA
kubectl certificate approve vault-csr
# Write public certificate to file
kubectl get csr vault-csr -o jsonpath='{.status.certificate}' | openssl base64 -d -A -out ${CERT_DIR}/vault.crt

Retrieve Kubernetes CA certificate

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

Create Kubernetes secret containing TLS certificate & CA

kubectl create secret generic ${SECRET_NAME} \
--namespace vault \
--from-file=vault.key=${CERT_DIR}/vault.key \
--from-file=vault.crt=${CERT_DIR}/vault.crt \
--from-file=ca.crt=${CERT_DIR}/vault.ca

Update Vault Helm values

vault:
  server:
    extraEnvironmentVars:
      VAULT_CACERT: /vault/userconfig/vault-server-tls/ca.crt
    extraVolumes:
      - type: secret
        name: vault-server-tls
        
    ha:
      raft:
        config: |
          ui = true

          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/ca.crt"
          }
          
          storage "raft" {
            path = "/vault/data"
              retry_join {
              leader_tls_servername = "*.vault-internal"
              leader_api_addr = "https://vault-0.vault-internal:8200"
              leader_client_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"
              leader_client_key_file = "/vault/userconfig/vault-server-tls/vault.key"
              leader_ca_cert_file = "/vault/userconfig/vault-server-tls/ca.crt"
            }
          
            retry_join {
              leader_tls_servername = "*.vault-internal"
              leader_api_addr = "https://vault-1.vault-internal:8200"
              leader_client_cert_file = "/vault/userconfig/vault-server-tls/vault.crt"
              leader_client_key_file = "/vault/userconfig/vault-server-tls/vault.key"
              leader_ca_cert_file = "/vault/userconfig/vault-server-tls/ca.crt"
            }    
          }

Setup Vault backup kubernetes cronjob

Configure backup auth

TOKEN_REVIEWER_JWT=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
vault write auth/kubernetes/config \
    token_reviewer_jwt="${TOKEN_REVIEWER_JWT}" \
    kubernetes_host="https://${KUBERNETES_PORT_443_TCP_ADDR}:443" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
path "sys/storage/raft/snapshot" {
  capabilities = ["read"]
}
vault write auth/kubernetes/role/backup \
bound_service_account_names=vault \
bound_service_account_namespaces=vault \
token_ttl=120m \
policies=backup

Create backup cronjob

download
apiVersion: batch/v1
kind: CronJob
metadata:
  name: vault-backup
  namespace: vault
spec:
  schedule: "0 */2 * * *"
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: vault
          volumes:
            - name: share
              emptyDir: {}
            - name: vault-server-tls
              secret:
                secretName: vault-server-tls
          initContainers:
            # Run an init container that creates the the snapshot of Vault
            - name: vault-snapshot
              image: hashicorp/vault:1.14.1
              command: ["/bin/sh", "-c"]
              args:
                # 1. Get the ServiceAccount token which we will use to authenticate against Vault
                # 2. Login to Vault using the SA token at the endpoint where the Kubernetes auth engine
                #    has been enabled
                # 3. Use the Vault CLI to store a snapshot in our empty volume
                - |
                  SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token);
                  export VAULT_TOKEN=$(vault write -field=token auth/kubernetes/login jwt=$SA_TOKEN role=backup);
                  vault operator raft snapshot save /share/vault.snap;
              env:
                - name: VAULT_ADDR
                  value: https://vault.vault.svc.cluster.local:8200
                - name: VAULT_CLIENT_CERT
                  value: /etc/vault-ssl/vault.crt
                - name: VAULT_CLIENT_KEY
                  value: /etc/vault-ssl/vault.key
                - name: VAULT_CACERT
                  value: /etc/vault-ssl/ca.crt
              volumeMounts:
                - mountPath: /share
                  name: share
                - mountPath: /etc/vault-ssl/
                  name: vault-server-tls
          containers:
            # Run a container with the AWS CLI and copy the snapshot to our S3 bucket
            - name: aws-s3-backup
              image: amazon/aws-cli:2.2.14
              command:
                - /bin/sh
              args:
                - -ec
                - aws s3 cp /share/vault.snap s3://my-backup-bucket/vault/vault_$(date +"%Y%m%d_%H%M%S").snap;
              volumeMounts:
                - mountPath: /share
                  name: share
          restartPolicy: OnFailure