Instal Vault di Kubernetes

Vault adalah tools yang digunakan untuk mengelola secrets seperti password, API key, token, dan sertifikat secara tersentralisasi, aman, dan dinamis. Dengan integrasi Vault dan Kubernetes, pod di Kubernetes dapat mengakses secrets tanpa harus menyimpannya langsung di konfigurasi atau environment variable, yang biasanya menjadi celah untuk dimanfaatkan attacker, karena mudah diakses.

Contoh penggunaan

  • Menyediakan kredensial database sementara ke pod.

  • Menyimpan dan mengelola sertifikat TLS untuk aplikasi.

  • Menghasilkan secrets sementara (dynamic secrets) yang otomatis kedaluwarsa.

Tutorial

Diuji di Kubernetes v1.32.3 dan OS Ubuntu Jammy

Tambahkan helm repo Vault

helm repo add hashicorp https://helm.releases.hashicorp.com

Buat temporary directory untuk menyimpan certificate

mkdir ~/vault

Generate private key

export VAULT_K8S_NAMESPACE="vault" \
export VAULT_HELM_RELEASE_NAME="vault" \
export VAULT_SERVICE_NAME="vault-internal" \
export K8S_CLUSTER_NAME="cluster.local" \
export WORKDIR=~/vault/
openssl genrsa -out ${WORKDIR}/vault.key 2048

Buat file konfigurasi CSR (Certificate Signing Request)

cat > ${WORKDIR}/vault-csr.conf <<EOF
[req]
default_bits = 2048
prompt = no
encrypt_key = yes
default_md = sha256
distinguished_name = kubelet_serving
req_extensions = v3_req
[ kubelet_serving ]
O = system:nodes
CN = system:node:*.${VAULT_K8S_NAMESPACE}.svc.${K8S_CLUSTER_NAME}
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = *.${VAULT_SERVICE_NAME}
DNS.2 = *.${VAULT_SERVICE_NAME}.${VAULT_K8S_NAMESPACE}.svc.${K8S_CLUSTER_NAME}
DNS.3 = *.${VAULT_K8S_NAMESPACE}
IP.1 = 127.0.0.1
EOF

Generate CSR

openssl req -new -key ${WORKDIR}/vault.key -out ${WORKDIR}/vault.csr -config ${WORKDIR}/vault-csr.conf

Buat CSR Yaml untuk Kubernetes

cat > ${WORKDIR}/csr.yaml <<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
   name: vault.svc
spec:
   signerName: kubernetes.io/kubelet-serving
   expirationSeconds: 8640000
   request: $(cat ${WORKDIR}/vault.csr|base64|tr -d '\n')
   usages:
   - digital signature
   - key encipherment
   - server auth
EOF
kubectl create -f ${WORKDIR}/csr.yaml

Approve CSR

kubectl certificate approve vault.svc

Pastikan certificate sudah issued

kubectl get csr vault.svc

Buat certificate CRT

kubectl get csr vault.svc -o jsonpath='{.status.certificate}' | openssl base64 -d -A -out ${WORKDIR}/vault.crt

Buat certificate CA

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

Buat namespace

kubectl create namespace $VAULT_K8S_NAMESPACE

Buat TLS secret

kubectl create secret generic vault-ha-tls \
   -n $VAULT_K8S_NAMESPACE \
   --from-file=vault.key=${WORKDIR}/vault.key \
   --from-file=vault.crt=${WORKDIR}/vault.crt \
   --from-file=vault.ca=${WORKDIR}/vault.ca

Deploy Vault

cat > ${WORKDIR}/overrides.yaml <<EOF
global:
   enabled: true
   tlsDisable: false
injector:
   enabled: true
server:
   extraEnvironmentVars:
      VAULT_CACERT: /vault/userconfig/vault-ha-tls/vault.ca
      VAULT_TLSCERT: /vault/userconfig/vault-ha-tls/vault.crt
      VAULT_TLSKEY: /vault/userconfig/vault-ha-tls/vault.key
   volumes:
      - name: userconfig-vault-ha-tls
        secret:
         defaultMode: 420
         secretName: vault-ha-tls
   volumeMounts:
      - mountPath: /vault/userconfig/vault-ha-tls
        name: userconfig-vault-ha-tls
        readOnly: true
   standalone:
      enabled: false
   affinity: ""
   ha:
      enabled: true
      replicas: 2
      raft:
         enabled: true
         setNodeId: true
         config: |
            cluster_name = "vault-integrated-storage"
            ui = true
            listener "tcp" {
               tls_disable = 0
               address = "[::]:8200"
               cluster_address = "[::]:8201"
               tls_cert_file = "/vault/userconfig/vault-ha-tls/vault.crt"
               tls_key_file  = "/vault/userconfig/vault-ha-tls/vault.key"
               tls_client_ca_file = "/vault/userconfig/vault-ha-tls/vault.ca"
            }
            storage "raft" {
               path = "/vault/data"
            }
            disable_mlock = true
            service_registration "kubernetes" {}
ui:
  enabled: true
  serviceType: "NodePort"
  serviceNodePort: null
  externalPort: 8200
EOF
helm install -n $VAULT_K8S_NAMESPACE $VAULT_HELM_RELEASE_NAME hashicorp/vault -f ${WORKDIR}/overrides.yaml

Inisialisasi vault-0 dengan satu key dan satu key threshold, artinya kita membuat satu key dan butuh satu key untuk membuka Vault.

kubectl exec -n $VAULT_K8S_NAMESPACE vault-0 -- vault operator init \
    -key-shares=1 \
    -key-threshold=1 \
    -format=json > ${WORKDIR}/cluster-keys.json

Untuk melihat unseal key

jq -r ".unseal_keys_b64[]" ${WORKDIR}/cluster-keys.json

Buat variable untuk capture unseal key

VAULT_UNSEAL_KEY=$(jq -r ".unseal_keys_b64[]" ${WORKDIR}/cluster-keys.json)

Unseal vault-0

kubectl exec -n $VAULT_K8S_NAMESPACE vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY

Joinkan vault-1 ke raft cluster

kubectl exec -n $VAULT_K8S_NAMESPACE -it vault-1 -- /bin/sh
vault operator raft join -address=https://vault-1.vault-internal:8200 -leader-ca-cert="$(cat /vault/userconfig/vault-ha-tls/vault.ca)" -leader-client-cert="$(cat /vault/userconfig/vault-ha-tls/vault.crt)" -leader-client-key="$(cat /vault/userconfig/vault-ha-tls/vault.key)" https://vault-0.vault-internal:8200
exit

Unseal vault-1

kubectl exec -n $VAULT_K8S_NAMESPACE -ti vault-1 -- vault operator unseal $VAULT_UNSEAL_KEY

Export cluster root token

export CLUSTER_ROOT_TOKEN=$(cat ${WORKDIR}/cluster-keys.json | jq -r ".root_token")

Login ke vault-0

kubectl exec -n $VAULT_K8S_NAMESPACE vault-0 -- vault login $CLUSTER_ROOT_TOKEN
...
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                hvs.NcFnpImyX3GHFrKCvqTaWyvB
token_accessor       HFdFIRYZojPRiTPgDLRldkic
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]
...

List raft peers

kubectl exec -n $VAULT_K8S_NAMESPACE vault-0 -- vault operator raft list-peers
...
Node       Address                        State       Voter
----       -------                        -----       -----
vault-0    vault-0.vault-internal:8201    leader      true
vault-1    vault-1.vault-internal:8201    follower    true
...

Access Vault UI, login dengan root token.

cat ${WORKDIR}/cluster-keys.json | jq -r ".root_token"
kubectl -n $VAULT_K8S_NAMESPACE get svc | grep vault-ui
...
vault-ui                   NodePort    10.101.40.205    <none>        8200:30826/TCP      20h
...

Referensi

0
Subscribe to my newsletter

Read articles from Rivaldy Ahmad Azhar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rivaldy Ahmad Azhar
Rivaldy Ahmad Azhar