apiVersion: v1 kind: ConfigMap metadata: name: vault-backup-script namespace: vault labels: app.kubernetes.io/name: vault-backup-script app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault data: backup.sh: | echo " "; echo ">> Running S3 backup for Vault snapshot"; OUTPUT=$(s3cmd sync --no-check-certificate -v /opt/backup/* "${BUCKET}/cl01tl/cl01tl-vault-snapshots/" 2>&1) STATUS=$? if [ $STATUS -ne 0 ]; then if echo "$OUTPUT" | grep -q "403 Forbidden"; then MESSAGE="403 Authentication Error: Your keys are wrong or you don't have permission" elif echo "$OUTPUT" | grep -q "404 Not Found"; then MESSAGE="404 Error: The bucket or folder does not exist" elif echo "$OUTPUT" | grep -q "Connection refused"; then MESSAGE="Network Error: Cannot reach the S3 endpoint" else MESSAGE="Unknown Error" echo " "; echo ">> Unknown Error, output:" echo " " echo "$OUTPUT" fi MAX_RETRIES=5 SUCCESS=false echo " " echo ">> Sending message to ntfy using curl ..." echo " " echo ">> Verifying required commands ..." for i in $(seq 1 "$MAX_RETRIES"); do if apk update 2>&1 >/dev/null; then echo ">> Attempt $i: Repositories are reachable"; SUCCESS=true; break; else echo ">> Attempt $i: Connection failed, retrying in 5 seconds ..."; sleep 5; fi; done; if [ "$SUCCESS" = false ]; then echo ">> ERROR: Could not connect to apk repositories after $MAX_RETRIES attempts, exiting ..."; exit 1; fi if ! command -v curl 2>&1 >/dev/null; then echo ">> Command curl could not be found, installing"; apk add --no-cache -q curl; if [ $? -eq 0 ]; then echo ">> Installation successful"; else echo ">> Installation failed with exit code $?"; exit 1; fi; fi; echo " " echo ">> Sending to NTFY ..." echo ">> Message: $MESSAGE" HTTP_STATUS=$(curl \ --silent \ --write-out '%{http_code}' \ -H "Authorization: Bearer ${NTFY_TOKEN}" \ -H "X-Priority: 5" \ -H "X-Tags: warning" \ -H "X-Title: Vault Backup Failed for ${TARGET}" \ -d "$MESSAGE" \ ${NTFY_ENDPOINT}/${NTFY_TOPIC} ) echo ">> HTTP Status Code: $HTTP_STATUS" else echo " "; echo ">> S3 Sync succeeded" fi --- apiVersion: v1 kind: ConfigMap metadata: name: vault-config namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm data: extraconfig-from-values.hcl: |- ui = true listener "tcp" { tls_disable = 1 address = "[::]:8200" cluster_address = "[::]:8201" telemetry { unauthenticated_metrics_access = "true" } } storage "raft" { path = "/vault/data" retry_join { leader_api_addr = "http://vault-0.vault-internal:8200" } retry_join { leader_api_addr = "http://vault-1.vault-internal:8200" } retry_join { leader_api_addr = "http://vault-2.vault-internal:8200" } } service_registration "kubernetes" {} telemetry { prometheus_retention_time = "30s" disable_hostname = true } disable_mlock = true --- apiVersion: v1 kind: ConfigMap metadata: name: vault-snapshot-script namespace: vault labels: app.kubernetes.io/name: vault-snapshot-script app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault data: snapshot.sh: | DATE=$(date +"%Y%m%d-%H-%M") MAX_RETRIES=5 SUCCESS=false echo " " echo ">> Running Vault Snapshot Script ..." echo " " echo ">> Verifying required commands ..." echo " " for i in $(seq 1 "$MAX_RETRIES"); do if apk update 2>&1 >/dev/null; then echo ">> Attempt $i: Repositories are reachable"; SUCCESS=true; break; else echo ">> Attempt $i: Connection failed, retrying in 5 seconds ..."; sleep 5; fi; done; if [ "$SUCCESS" = false ]; then echo ">> ERROR: Could not connect to apk repositories after $MAX_RETRIES attempts, exiting ..."; exit 1; fi echo " " if ! command -v jq 2>&1 >/dev/null; then echo ">> Command jq could not be found, installing"; apk add --no-cache -q jq; if [ $? -eq 0 ]; then echo ">> Installation successful"; else echo ">> Installation failed with exit code $?"; exit 1; fi; fi; echo " "; echo ">> Fetching Vault token ..."; export VAULT_TOKEN=$(vault write auth/approle/login role_id=$VAULT_APPROLE_ROLE_ID secret_id=$VAULT_APPROLE_SECRET_ID -format=json | jq -r .auth.client_token); echo " "; echo ">> Taking Vault snapsot ..."; vault operator raft snapshot save /opt/backup/vault-snapshot-$DATE.snap echo " "; echo ">> Setting ownership of Vault snapsot ..."; chown 100:1000 /opt/backup/vault-snapshot-$DATE.snap echo " "; echo ">> Completed Vault snapshot"; --- apiVersion: batch/v1 kind: CronJob metadata: name: vault-snapshot labels: app.kubernetes.io/controller: snapshot app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: vault helm.sh/chart: snapshot-4.6.2 namespace: vault spec: suspend: false concurrencyPolicy: Forbid startingDeadlineSeconds: 90 timeZone: US/Central schedule: "0 4 * * *" successfulJobsHistoryLimit: 1 failedJobsHistoryLimit: 3 jobTemplate: spec: parallelism: 1 backoffLimit: 3 template: metadata: labels: app.kubernetes.io/controller: snapshot app.kubernetes.io/instance: vault app.kubernetes.io/name: vault spec: enableServiceLinks: false serviceAccountName: default automountServiceAccountToken: true hostIPC: false hostNetwork: false hostPID: false dnsPolicy: ClusterFirst restartPolicy: Never initContainers: - args: - -ec - /scripts/snapshot.sh command: - /bin/ash env: - name: VAULT_ADDR value: http://vault-active.vault.svc.cluster.local:8200 envFrom: - secretRef: name: vault-snapshot-agent-token image: hashicorp/vault:1.21.4 imagePullPolicy: IfNotPresent name: snapshot volumeMounts: - mountPath: /opt/backup name: backup - mountPath: /scripts/snapshot.sh name: snapshot-script subPath: snapshot.sh containers: - args: - -ec - /scripts/backup.sh command: - /bin/sh env: - name: BUCKET valueFrom: secretKeyRef: key: BUCKET name: vault-s3cmd-external-config - name: TARGET value: External envFrom: - secretRef: name: vault-backup-ntfy-secret image: d3fk/s3cmd:latest@sha256:a41234c2b43d6cfa0d51c9523a2d7925f7f21297a41d69932946c3e364d32b5e imagePullPolicy: IfNotPresent name: s3-backup-external volumeMounts: - mountPath: /opt/backup name: backup - mountPath: /scripts/backup.sh name: backup-script subPath: backup.sh - mountPath: /root/.s3cfg mountPropagation: None name: s3cmd-external-config readOnly: true subPath: .s3cfg - args: - -ec - /scripts/backup.sh command: - /bin/sh env: - name: BUCKET valueFrom: secretKeyRef: key: BUCKET name: vault-s3cmd-local-config - name: TARGET value: Local envFrom: - secretRef: name: vault-backup-ntfy-secret image: d3fk/s3cmd:latest@sha256:a41234c2b43d6cfa0d51c9523a2d7925f7f21297a41d69932946c3e364d32b5e imagePullPolicy: IfNotPresent name: s3-backup-local volumeMounts: - mountPath: /opt/backup name: backup - mountPath: /scripts/backup.sh name: backup-script subPath: backup.sh - mountPath: /root/.s3cfg mountPropagation: None name: s3cmd-local-config readOnly: true subPath: .s3cfg - args: - -ec - /scripts/backup.sh command: - /bin/sh env: - name: BUCKET valueFrom: secretKeyRef: key: BUCKET name: vault-s3cmd-remote-config - name: TARGET value: Remote envFrom: - secretRef: name: vault-backup-ntfy-secret image: d3fk/s3cmd:latest@sha256:a41234c2b43d6cfa0d51c9523a2d7925f7f21297a41d69932946c3e364d32b5e imagePullPolicy: IfNotPresent name: s3-backup-remote volumeMounts: - mountPath: /opt/backup name: backup - mountPath: /scripts/backup.sh name: backup-script subPath: backup.sh - mountPath: /root/.s3cfg mountPropagation: None name: s3cmd-remote-config readOnly: true subPath: .s3cfg volumes: - name: backup persistentVolumeClaim: claimName: vault-storage-backup - configMap: defaultMode: 493 name: vault-backup-script name: backup-script - name: s3cmd-external-config secret: secretName: vault-s3cmd-external-config - name: s3cmd-local-config secret: secretName: vault-s3cmd-local-config - name: s3cmd-remote-config secret: secretName: vault-s3cmd-remote-config - configMap: defaultMode: 493 name: vault-snapshot-script name: snapshot-script --- apiVersion: apps/v1 kind: Deployment metadata: name: vault-unseal-unseal-1 labels: app.kubernetes.io/controller: unseal-1 app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: vault helm.sh/chart: unseal-4.6.2 namespace: vault spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/controller: unseal-1 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault template: metadata: labels: app.kubernetes.io/controller: unseal-1 app.kubernetes.io/instance: vault app.kubernetes.io/name: vault spec: enableServiceLinks: false serviceAccountName: default automountServiceAccountToken: true hostIPC: false hostNetwork: false hostPID: false dnsPolicy: ClusterFirst containers: - envFrom: - secretRef: name: vault-unseal-config-1 image: ghcr.io/lrstanley/vault-unseal:0.7.2 imagePullPolicy: IfNotPresent name: main resources: requests: cpu: 10m memory: 24Mi --- apiVersion: apps/v1 kind: Deployment metadata: name: vault-unseal-unseal-2 labels: app.kubernetes.io/controller: unseal-2 app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: vault helm.sh/chart: unseal-4.6.2 namespace: vault spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/controller: unseal-2 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault template: metadata: labels: app.kubernetes.io/controller: unseal-2 app.kubernetes.io/instance: vault app.kubernetes.io/name: vault spec: enableServiceLinks: false serviceAccountName: default automountServiceAccountToken: true hostIPC: false hostNetwork: false hostPID: false dnsPolicy: ClusterFirst containers: - envFrom: - secretRef: name: vault-unseal-config-2 image: ghcr.io/lrstanley/vault-unseal:0.7.2 imagePullPolicy: IfNotPresent name: main resources: requests: cpu: 10m memory: 24Mi --- apiVersion: apps/v1 kind: Deployment metadata: name: vault-unseal-unseal-3 labels: app.kubernetes.io/controller: unseal-3 app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: vault helm.sh/chart: unseal-4.6.2 namespace: vault spec: revisionHistoryLimit: 3 replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/controller: unseal-3 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault template: metadata: labels: app.kubernetes.io/controller: unseal-3 app.kubernetes.io/instance: vault app.kubernetes.io/name: vault spec: enableServiceLinks: false serviceAccountName: default automountServiceAccountToken: true hostIPC: false hostNetwork: false hostPID: false dnsPolicy: ClusterFirst containers: - envFrom: - secretRef: name: vault-unseal-config-3 image: ghcr.io/lrstanley/vault-unseal:0.7.2 imagePullPolicy: IfNotPresent name: main resources: requests: cpu: 10m memory: 24Mi --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-backup-ntfy-secret namespace: vault labels: app.kubernetes.io/name: vault-backup-ntfy-secret app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: NTFY_TOKEN remoteRef: conversionStrategy: Default decodingStrategy: None key: /ntfy/user/cl01tl metadataPolicy: None property: token - secretKey: NTFY_ENDPOINT remoteRef: conversionStrategy: Default decodingStrategy: None key: /ntfy/user/cl01tl metadataPolicy: None property: endpoint - secretKey: NTFY_TOPIC remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/snapshot metadataPolicy: None property: NTFY_TOPIC --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-s3cmd-external-config namespace: vault labels: app.kubernetes.io/name: vault-s3cmd-external-config app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: .s3cfg remoteRef: conversionStrategy: Default decodingStrategy: None key: /digital-ocean/home-infra/vault-backup metadataPolicy: None property: s3cfg - secretKey: BUCKET remoteRef: conversionStrategy: Default decodingStrategy: None key: /digital-ocean/home-infra/vault-backup metadataPolicy: None property: BUCKET --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-s3cmd-local-config namespace: vault labels: app.kubernetes.io/name: vault-s3cmd-local-config app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: .s3cfg remoteRef: conversionStrategy: Default decodingStrategy: None key: /garage/home-infra/vault-backups metadataPolicy: None property: s3cfg-local - secretKey: BUCKET remoteRef: conversionStrategy: Default decodingStrategy: None key: /garage/home-infra/vault-backups metadataPolicy: None property: BUCKET --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-s3cmd-remote-config namespace: vault labels: app.kubernetes.io/name: vault-s3cmd-remote-config app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: .s3cfg remoteRef: conversionStrategy: Default decodingStrategy: None key: /garage/home-infra/vault-backups metadataPolicy: None property: s3cfg-remote - secretKey: BUCKET remoteRef: conversionStrategy: Default decodingStrategy: None key: /garage/home-infra/vault-backups metadataPolicy: None property: BUCKET --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-snapshot-agent-token namespace: vault labels: app.kubernetes.io/name: vault-snapshot-agent-token app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: VAULT_APPROLE_ROLE_ID remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/snapshot metadataPolicy: None property: VAULT_APPROLE_ROLE_ID - secretKey: VAULT_APPROLE_SECRET_ID remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/snapshot metadataPolicy: None property: VAULT_APPROLE_SECRET_ID --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-token namespace: vault labels: app.kubernetes.io/name: vault-token app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: token remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: token - secretKey: unseal_key_1 remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: unseal_key_1 - secretKey: unseal_key_2 remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: unseal_key_2 - secretKey: unseal_key_3 remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: unseal_key_3 - secretKey: unseal_key_4 remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: unseal_key_4 - secretKey: unseal_key_5 remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/token metadataPolicy: None property: unseal_key_5 --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-unseal-config-1 namespace: vault labels: app.kubernetes.io/name: vault-unseal-config-1 app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: ENVIRONMENT remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: ENVIRONMENT - secretKey: CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: CHECK_INTERVAL - secretKey: MAX_CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: MAX_CHECK_INTERVAL - secretKey: NODES remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: NODES - secretKey: TLS_SKIP_VERIFY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: TLS_SKIP_VERIFY - secretKey: TOKENS remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: TOKENS - secretKey: EMAIL_ENABLED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: EMAIL_ENABLED - secretKey: NOTIFY_MAX_ELAPSED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: NOTIFY_MAX_ELAPSED - secretKey: NOTIFY_QUEUE_DELAY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-1 metadataPolicy: None property: NOTIFY_QUEUE_DELAY --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-unseal-config-2 namespace: vault labels: app.kubernetes.io/name: vault-unseal-config-2 app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: ENVIRONMENT remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: ENVIRONMENT - secretKey: CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: CHECK_INTERVAL - secretKey: MAX_CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: MAX_CHECK_INTERVAL - secretKey: NODES remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: NODES - secretKey: TLS_SKIP_VERIFY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: TLS_SKIP_VERIFY - secretKey: TOKENS remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: TOKENS - secretKey: EMAIL_ENABLED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: EMAIL_ENABLED - secretKey: NOTIFY_MAX_ELAPSED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: NOTIFY_MAX_ELAPSED - secretKey: NOTIFY_QUEUE_DELAY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-2 metadataPolicy: None property: NOTIFY_QUEUE_DELAY --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: vault-unseal-config-3 namespace: vault labels: app.kubernetes.io/name: vault-unseal-config-3 app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: secretStoreRef: kind: ClusterSecretStore name: vault data: - secretKey: ENVIRONMENT remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: ENVIRONMENT - secretKey: CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: CHECK_INTERVAL - secretKey: MAX_CHECK_INTERVAL remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: MAX_CHECK_INTERVAL - secretKey: NODES remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: NODES - secretKey: TLS_SKIP_VERIFY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: TLS_SKIP_VERIFY - secretKey: TOKENS remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: TOKENS - secretKey: EMAIL_ENABLED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: EMAIL_ENABLED - secretKey: NOTIFY_MAX_ELAPSED remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: NOTIFY_MAX_ELAPSED - secretKey: NOTIFY_QUEUE_DELAY remoteRef: conversionStrategy: Default decodingStrategy: None key: /cl01tl/vault/unseal/config-3 metadataPolicy: None property: NOTIFY_QUEUE_DELAY --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: vault namespace: vault labels: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: traefik-gateway namespace: traefik hostnames: - vault.alexlebens.net rules: - matches: - path: type: PathPrefix value: / backendRefs: - group: '' kind: Service name: vault-active port: 8200 weight: 100 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: vault-tailscale namespace: vault labels: app.kubernetes.io/name: vault-tailscale app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault tailscale.com/proxy-class: no-metrics annotations: tailscale.com/experimental-forward-cluster-traffic-via-ingress: "true" spec: ingressClassName: tailscale tls: - hosts: - vault-cl01tl secretName: vault-cl01tl rules: - host: vault-cl01tl http: paths: - path: / pathType: Prefix backend: service: name: vault-active port: number: 8200 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: vault-storage-backup namespace: vault labels: app.kubernetes.io/name: vault-storage-backup app.kubernetes.io/instance: vault app.kubernetes.io/part-of: vault spec: volumeMode: Filesystem storageClassName: ceph-filesystem accessModes: - ReadWriteMany resources: requests: storage: 1Gi --- apiVersion: v1 kind: Pod metadata: name: vault-server-test namespace: vault annotations: "helm.sh/hook": test spec: containers: - name: vault-server-test image: hashicorp/vault:1.21.4 imagePullPolicy: IfNotPresent env: - name: VAULT_ADDR value: http://vault.vault.svc:8200 command: - /bin/sh - -c - | echo "Checking for sealed info in 'vault status' output" ATTEMPTS=10 n=0 until [ "$n" -ge $ATTEMPTS ] do echo "Attempt" $n... vault status -format yaml | grep -E '^sealed: (true|false)' && break n=$((n+1)) sleep 5 done if [ $n -ge $ATTEMPTS ]; then echo "timed out looking for sealed info in 'vault status' output" exit 1 fi exit 0 volumeMounts: - mountPath: /opt/backups/ name: vault-storage-backup readOnly: false volumes: - name: vault-storage-backup persistentVolumeClaim: claimName: vault-storage-backup restartPolicy: Never --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: vault namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server --- apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm release: prometheus spec: groups: - name: vault rules: - alert: vault-HighResponseTime annotations: message: The response time of Vault is over 500ms on average over the last 5 minutes. expr: vault_core_handle_request{quantile="0.5", namespace="mynamespace"} > 500 for: 5m labels: severity: warning - alert: vault-HighResponseTime annotations: message: The response time of Vault is over 1s on average over the last 5 minutes. expr: vault_core_handle_request{quantile="0.5", namespace="mynamespace"} > 1000 for: 5m labels: severity: critical --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: vault name: vault-discovery-role labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: vault-discovery-rolebinding namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: vault-discovery-role subjects: - kind: ServiceAccount name: vault namespace: vault --- apiVersion: v1 kind: Service metadata: name: vault-active namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm vault-active: "true" annotations: spec: type: ClusterIP publishNotReadyAddresses: true ports: - name: http port: 8200 targetPort: 8200 - name: https-internal port: 8201 targetPort: 8201 selector: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server vault-active: "true" --- apiVersion: v1 kind: Service metadata: name: vault-internal namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm vault-internal: "true" annotations: spec: clusterIP: None publishNotReadyAddresses: true ports: - name: "http" port: 8200 targetPort: 8200 - name: https-internal port: 8201 targetPort: 8201 selector: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server --- apiVersion: v1 kind: Service metadata: name: vault-ui namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault-ui app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm spec: selector: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server publishNotReadyAddresses: true ports: - name: http port: 8200 targetPort: 8200 type: ClusterIP --- apiVersion: v1 kind: Service metadata: name: vault namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm annotations: spec: type: ClusterIP publishNotReadyAddresses: true ports: - name: http port: 8200 targetPort: 8200 - name: https-internal port: 8201 targetPort: 8201 selector: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server --- apiVersion: v1 kind: ServiceAccount metadata: name: vault namespace: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm --- apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: vault labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm release: prometheus spec: selector: matchLabels: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault vault-active: "true" endpoints: - port: http interval: 30s scrapeTimeout: 10s scheme: http path: /v1/sys/metrics params: format: - prometheus tlsConfig: insecureSkipVerify: true namespaceSelector: matchNames: - vault --- apiVersion: apps/v1 kind: StatefulSet metadata: name: vault namespace: vault labels: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault app.kubernetes.io/managed-by: Helm spec: serviceName: vault-internal podManagementPolicy: Parallel replicas: 3 updateStrategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server template: metadata: labels: helm.sh/chart: vault-0.32.0 app.kubernetes.io/name: vault app.kubernetes.io/instance: vault component: server annotations: spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app.kubernetes.io/name: vault app.kubernetes.io/instance: "vault" component: server topologyKey: kubernetes.io/hostname terminationGracePeriodSeconds: 10 serviceAccountName: vault securityContext: runAsNonRoot: true runAsGroup: 1000 runAsUser: 100 fsGroup: 1000 hostNetwork: false volumes: - name: config configMap: name: vault-config - name: vault-storage-backup persistentVolumeClaim: claimName: vault-storage-backup - name: home emptyDir: {} containers: - name: vault resources: requests: cpu: 50m memory: 512Mi image: hashicorp/vault:1.21.4 imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-ec" args: - "cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl;\n[ -n \"${HOST_IP}\" ] && sed -Ei \"s|HOST_IP|${HOST_IP?}|g\" /tmp/storageconfig.hcl;\n[ -n \"${POD_IP}\" ] && sed -Ei \"s|POD_IP|${POD_IP?}|g\" /tmp/storageconfig.hcl;\n[ -n \"${HOSTNAME}\" ] && sed -Ei \"s|HOSTNAME|${HOSTNAME?}|g\" /tmp/storageconfig.hcl;\n[ -n \"${API_ADDR}\" ] && sed -Ei \"s|API_ADDR|${API_ADDR?}|g\" /tmp/storageconfig.hcl;\n[ -n \"${TRANSIT_ADDR}\" ] && sed -Ei \"s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g\" /tmp/storageconfig.hcl;\n[ -n \"${RAFT_ADDR}\" ] && sed -Ei \"s|RAFT_ADDR|${RAFT_ADDR?}|g\" /tmp/storageconfig.hcl;\n/usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl \n" securityContext: allowPrivilegeEscalation: false env: - name: HOST_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: VAULT_K8S_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: VAULT_K8S_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: VAULT_ADDR value: "http://127.0.0.1:8200" - name: VAULT_API_ADDR value: "http://$(POD_IP):8200" - name: SKIP_CHOWN value: "true" - name: SKIP_SETCAP value: "true" - name: HOSTNAME valueFrom: fieldRef: fieldPath: metadata.name - name: VAULT_CLUSTER_ADDR value: "https://$(HOSTNAME).vault-internal:8201" - name: HOME value: "/home/vault" - name: VAULT_LOG_LEVEL value: "debug" - name: VAULT_LOG_FORMAT value: "standard" volumeMounts: - name: data mountPath: /vault/data - name: config mountPath: /vault/config - mountPath: /opt/backups/ name: vault-storage-backup readOnly: false - name: home mountPath: /home/vault ports: - containerPort: 8200 name: http - containerPort: 8201 name: https-internal - containerPort: 8202 name: http-rep readinessProbe: exec: command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] failureThreshold: 2 initialDelaySeconds: 5 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 3 lifecycle: preStop: exec: command: - "/bin/sh" - "-c" - "sleep 5 && kill -SIGTERM $(pidof vault)" volumeClaimTemplates: - apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi