Intoduction
HashiCorp Vault adalah sistem manajemen rahasia (secret management) yang digunakan untuk menyimpan, mengelola, dan mengontrol akses terhadap data sensitif seperti password, token, dan sertifikat secara aman. Dalam lingkungan produksi, keandalan dan ketersediaan tinggi (High Availability/HA) menjadi hal yang sangat penting agar layanan tetap dapat diakses meskipun terjadi kegagalan pada salah satu node.
Configuration TLS for Vault HA
1. Create Self-signed certificate
Kita akan membuat self-signed certificate untuk ssl pada vault yang akan kita install. Pada tutorial disini kita akan membuat certificate menggunakan openssl. Kita akan menggunakan referensi dari konfiguarsi resmi vault https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-minikube-tls
Change working directory
mkdir -p ~/vault/cert
cd ~/vault/certGenerate private key
openssl genrsa -out vault.key 2048Create CSR configuration
cat > 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.vault.svc
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = vault.vault.svc
DNS.2 = vault.vault.svc.cluster.local
DNS.3 = *.vault-internal
IP.1 = 127.0.0.1
EOFGenerate file CSR
openssl req -new -key vault.key -out vault.csr -config vault-csr.conf2. Issue Certificate
Kita sudah selesai generate certificate, sekarang kita akan melakukan issue certificate yang sudah kita generate ke kubernetes
Create CSR yaml
cat > csr.yaml << EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: vault.svc
spec:
signerName: kubernetes.io/kubelet-serving
expirationSeconds: 8640000
request: $(cat vault.csr|base64|tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOFApply file CSR ke kubernetes dan approve certificate tersebut
kubectl create -f csr.yaml
kubectl certificate approve vault.svc3. Store the certificates and Key in the Kubernetes secrets store
Ambil certificate yang sudah kita approve
kubectl get csr vault.svc -o jsonpath='{.status.certificate}' | openssl base64 -d -A -out vault.crtAmbil certificate CA
kubectl config view \
--raw \
--minify \
--flatten \
-o jsonpath='{.clusters[].cluster.certificate-authority-data}' \
| base64 -d > vault.caCreate namespace
kubectl create ns vaultBuat TLS Secret
kubectl create secret generic vault-ha-tls \
-n vault \
--from-file=vault.key=vault.key \
--from-file=vault.crt=vault.crt \
--from-file=vault.ca=vault.caInstallation & Configuration Vault
1. Install Vault using helm
Sekarang kita akan deploy vault menggunakan helm v3. Tambahkan repo hashicorp via helm
helm repo add hashicorp https://helm.releases.hashicorp.com
helm search repo hashicorp/vaultcreate files values.yaml
global:
enabled: true
tlsDisable: false
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 256Mi
cpu: 250m
server:
resources:
requests:
memory: 2Gi
cpu: 2000m
limits:
memory: 4Gi
cpu: 4000m
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
auditStorage:
enabled: false
standalone:
enabled: false
# Run Vault in "HA" mode.
ha:
enabled: true
replicas: 3
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" {}
# Vault UI
ui:
enabled: true
serviceType: "LoadBalancer"
loadBalancerIP: "10.100.19.93"
serviceNodePort: null
externalPort: 8200Install vault menggunakan values diatas menggunakan version 0.31.0 (terbaru pada saat blog ini ditulus)
helm install vault -n vault -f values.yaml --version 0.31.0 hashicorp/vault Check instalasi vault
kubectl get all -n vault
2. Init & unseal vault
Ketika kita sudah install vault, status pod masih belum ready karna kita harus unseal masing-masing pods.
Init vault disalah satu pod (vault-0)
kubectl exec -it -n vault vault-0 -- vault operator init
Kita akan mendapatkan 5 key, dan kita akan unseal vault-0 yang sudah kita init menggunakan 3 dari 5 key. Simpan key tersebut ketempat yang aman, karena kita akan membutuhkan key tersebut.
kubectl exec -it -n vault vault-0 -- vault operator unseal
Kita sudah init cluster dan unseal vault-0. Sekarang kita harus join raft-cluster dari vault-1 dan vault-2 ke raft-cluster
Exec terlebih dahulu vault-1
kubectl exec -it -n vault vault-1 -- shKemudian kita join cluster
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:8200Unseal vault-1
vault operator unsealSekarang untuk vault-2
kubectl exec -it -n vault vault-2 -- shKemudian kita join cluster
vault operator raft join -address=https://vault-2.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:8200Kemudian kita unseal vault-2
vault operator unsealcheck status vault
kubectl exec -it -n vault vault-1 -- vault status
kubectl exec -it -n vault vault-2 -- vault status
3.1 Configuration secret, policy, kubernetes auth (via CLI)
Ada 2 cara untuk konfiguarsi pada vault, bisa menggunakan CLI dan GUI. Pada tahap ini kita akan membuat secret, policy, dan kubernetes auth menggunakan CLI yang diexec dari vault-0.
Kita masuk exec vault-0
kubectl exec -it -n vault vault-0 -- shSecret Data
Kita membuat secret data menggunakan kv-v2
vault secrets enable -path=secret kv-v2
vault kv put secret/myapps/config username="usersaya" password="passwordsaya"Check apakah data sudah kesave
vault kv get secret/myapps/config
vault kv get -field=username secret/myapps/config
vault kv get -field=password secret/myapps/config
Policies
Kita membuat policy dengan nama myapps-policy
vault policy write myapps-policy - << EOF
path "secret/data/myapps/*" {
capabilities = ["read"]
}
EOFCheck policy
vault read sys/policy/myapps-policy
Kubernetes auth
Enable auto kubernetes
vault auth enable kubernetes
vault write auth/kubernetes/config \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" Buat role baru
vault write auth/kubernetes/role/myapps-role \
bound_service_account_names=myapps-sa \
bound_service_account_namespaces=myapps \
policies=myapps-policy \
ttl=24hChek role yang sudah dibuat
vault read auth/kubernetes/role/myapps-role
3.2 Configuration secret, policy, kubernetes auth (via GUI)
Pada tutorial ini kita akan menggunakan dashboard vault yang sudah kita install menggunakan LoadBalancerIP. Jika sudah disetup menggunakan CLI, kita bisa skip tahap ini.
Akses vault via browser

Untuk login kita bisa menggunakan token yang terdapat pada saat kita init vault (Initial root token)
Secret Data
Buat engine kv-v2 dengan cara, Secret Engine -> Enable new engine -> Pilih KV -> Isi path dengan nama secret

Setelah kita membuat engine, kita membuat secret baru, Create Secret -> kemudian isi path myapps/config dan dengan secret data sesuai kebutuhan kita

Policies
Sekarang kita akan membuat policy hanya bisa akses read ke secret tersebut, Policies -> Create ACL Policy -> kemudian kita beri nama policy myapps-policy dan acl
path "secret/data/myapps/*" {
capabilities = ["read"]
}
Kubernetes Auth
Sekarang kita akan konfiguarsi agar vault kita bisa terhubung ke kubernetes cluster, Access -> Enable new method -> Kubernetes -> Enable method (pathnya menggunakan default yaitu kubernetes)

Setelah kita enable kubernetes method, kita harus isi Kubernetes Host, untuk mengetahui IP Address kubernetes host kita bisa menggunakan kubectl
kubectl get all

Setelah itu kita membuat role baru

4. Testing vault to pods using vault-agent-injector
Sekarang kita akan menggunakan pods dan menggunakan annotation vault untuk melakukan inject ke pods. Pada tahap sebelumnya kita menggunakan service account myapps-sa.
Kita buat file manifest yang berisi service account dan pods
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapps-sa
namespace: myapps
---
apiVersion: v1
kind: Pod
metadata:
name: demo
namespace: myapps
# We will use annotation for inject the vault into pods
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/ca-cert: "/run/secrets/kubernetes.io/serviceaccount/ca.crt"
vault.hashicorp.com/role: "myapps-role"
vault.hashicorp.com/agent-inject-secret-testwithraw: "secret/myapps/config"
vault.hashicorp.com/agent-inject-template-testwithtemplate: |
{{- with secret "secret/data/myapps/config" -}}
username={{ .Data.data.username }}
password={{ .Data.data.password }}
{{- end }}
spec:
serviceAccountName: myapps-sa
containers:
- name: app
image: nginx
Sekarang kita apply file manifest tersebut kemudian check pods dan service-account tersebut
kubectl get all,sa -n myapps
Kemudian kita check vault secret didalam pods demo
kubectl exec -it -n myapps demo -c app -- ls /vault/secrets/
kubectl exec -it -n myapps demo -c app -- cat /vault/secrets/testwithraw
kubectl exec -it -n myapps demo -c app -- cat /vault/secrets/testwithtemplate
Secara default, letak secret vault ada di /vault/secrets/. Secret sudah bisa dibaca oleh pod dan sudah bisa digunakan
Troubleshooting
All pod is terminating
Ketika semua pods vault terminating, dan pada saat autostart, maka kita harus unseal pods tersebut menggunakan key (pada saat init) yang sudah disimpan.