# services/vault/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: vault
  namespace: vault
  labels:
    app: vault
spec:
  serviceName: vault-internal
  replicas: 1
  selector:
    matchLabels:
      app: vault
  template:
    metadata:
      labels:
        app: vault
    spec:
      serviceAccountName: vault
      nodeSelector:
        node-role.kubernetes.io/worker: "true"
        kubernetes.io/arch: arm64
      securityContext:
        fsGroup: 1000
      initContainers:
        - name: setup-config
          image: alpine:3.20
          command:
            - sh
            - -c
            - |
              set -euo pipefail
              cp /config-src/local.hcl /vault/config/local.hcl
              chown 1000:1000 /vault/config/local.hcl
              chmod 640 /vault/config/local.hcl
          securityContext:
            runAsUser: 0
            runAsGroup: 0
            allowPrivilegeEscalation: false
          volumeMounts:
            - name: config-template
              mountPath: /config-src
            - name: config
              mountPath: /vault/config
      containers:
        - name: vault
          image: hashicorp/vault:1.17.6
          imagePullPolicy: IfNotPresent
          command: ["vault"]
          args: ["server", "-config=/vault/config/local.hcl"]
          ports:
            - name: api
              containerPort: 8200
            - name: cluster
              containerPort: 8201
          env:
            - name: VAULT_ADDR
              value: "http://127.0.0.1:8200"
            - name: VAULT_API_ADDR
              value: "https://secret.bstein.dev"
            - name: VAULT_CLUSTER_ADDR
              value: "https://vault-0.vault-internal:8201"
            - name: VAULT_REDIRECT_ADDR
              value: "https://secret.bstein.dev"
            - name: VAULT_LOG_LEVEL
              value: "info"
            - name: VAULT_DISABLE_MLOCK
              value: "true"
            - name: VAULT_DISABLE_PERM_MGMT
              value: "true"
            - name: SKIP_CHOWN
              value: "true"
            - name: SKIP_SETCAP
              value: "true"
          readinessProbe:
            httpGet:
              path: /v1/sys/health?standbyok=true
              port: api
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 6
          livenessProbe:
            httpGet:
              path: /v1/sys/health?standbyok=true&sealedcode=204&uninitcode=204
              port: api
            initialDelaySeconds: 60
            periodSeconds: 20
            timeoutSeconds: 3
            failureThreshold: 6
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 1Gi
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            runAsGroup: 1000
            allowPrivilegeEscalation: false
            capabilities:
              add: ["IPC_LOCK"]
              drop: ["ALL"]
          volumeMounts:
            - name: config
              mountPath: /vault/config
            - name: data
              mountPath: /vault/data
            - name: tls
              mountPath: /vault/userconfig/tls
              readOnly: true
      volumes:
        - name: config-template
          configMap:
            name: vault-config
        - name: config
          emptyDir: {}
        - name: tls
          secret:
            secretName: vault-server-tls
            optional: false
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi
        storageClassName: astreae
