├── README.md ├── crontab.sh ├── vault-injector-manifests ├── deployment.yaml ├── mutating-webhook.yaml ├── rbac.yaml └── service.yaml └── vault-manifests ├── configmap.yaml ├── rbac.yaml ├── services.yaml └── statefulset.yaml /README.md: -------------------------------------------------------------------------------- 1 | # kubernetes-vault 2 | Kubernetes manifests to setup Hashicorp vault server 3 | 4 | Full Documentation: https://devopscube.com/vault-in-kubernetes/ 5 | 6 | #Sample API request to the vault using service account tokens to acquire a token with reading capabilities for path "demo-app" 7 | 8 | ``` 9 | curl --request POST --data '{"jwt": "<< service account token of the pod >>", "role": "webapp"}' http://192.168.49.2:30493/v1/auth/kubernetes/login 10 | ``` 11 | 12 | #Sample API request to the vault to fetch secrets at "demo-app" 13 | 14 | ``` 15 | curl -H "X-Vault-Token: " -H "X-Vault-Namespace: vault" -X GET http://192.168.49.2:30493/v1/demo-app/data/user01?version=1 16 | ``` 17 | 18 | ## Vault Usage 19 | 20 | ### Initialize the vault. 21 | 22 | ```kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > keys.json 23 | 24 | VAULT_UNSEAL_KEY=$(cat keys.json | jq -r ".unseal_keys_b64[]") 25 | echo $VAULT_UNSEAL_KEY 26 | 27 | VAULT_ROOT_KEY=$(cat keys.json | jq -r ".root_token") 28 | echo $VAULT_ROOT_KEY 29 | ``` 30 | 31 | ### Unseal the vault 32 | 33 | ```kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY ``` 34 | 35 | ### Login into the vault 36 | ```kubectl exec vault-0 -- vault login $VAULT_ROOT_KEY``` 37 | 38 | ### Create secrets 39 | 40 | ```vault secrets enable -version=2 -path="demo-app" kv``` 41 | 42 | ### Create key-value pairs 43 | ```vault kv put demo-app/user01 name=devopscube 44 | vault kv get demo-app/user01 45 | ``` 46 | ###Create policies 47 | ```vault policy write demo-policy - < keys.json 14 | VAULT_UNSEAL_KEY=$(cat keys.json | jq -r ".unseal_keys_b64[]") 15 | echo $VAULT_UNSEAL_KEY 16 | VAULT_ROOT_KEY=$(cat keys.json | jq -r ".root_token") 17 | echo $VAULT_ROOT_KEY 18 | kubectl exec vault-"$input1" -- vault operator unseal $VAULT_UNSEAL_KEY 19 | sleep 10 20 | done 21 | break 22 | else 23 | echo "false" 24 | fi 25 | else 26 | echo "None.No vault pod." 27 | fi 28 | done 29 | -------------------------------------------------------------------------------- /vault-injector-manifests/deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: vault-agent-injector 6 | namespace: default 7 | labels: 8 | app.kubernetes.io/name: vault-agent-injector 9 | app.kubernetes.io/instance: vault 10 | component: webhook 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app.kubernetes.io/name: vault-agent-injector 16 | app.kubernetes.io/instance: vault 17 | component: webhook 18 | template: 19 | metadata: 20 | labels: 21 | app.kubernetes.io/name: vault-agent-injector 22 | app.kubernetes.io/instance: vault 23 | component: webhook 24 | spec: 25 | 26 | affinity: 27 | podAntiAffinity: 28 | requiredDuringSchedulingIgnoredDuringExecution: 29 | - labelSelector: 30 | matchLabels: 31 | app.kubernetes.io/name: vault-agent-injector 32 | app.kubernetes.io/instance: "vault" 33 | component: webhook 34 | topologyKey: kubernetes.io/hostname 35 | serviceAccountName: "vault-agent-injector" 36 | hostNetwork: false 37 | securityContext: 38 | runAsNonRoot: true 39 | runAsGroup: 1000 40 | runAsUser: 100 41 | containers: 42 | - name: sidecar-injector 43 | 44 | image: "hashicorp/vault-k8s:0.11.0" 45 | imagePullPolicy: "IfNotPresent" 46 | securityContext: 47 | allowPrivilegeEscalation: false 48 | env: 49 | - name: AGENT_INJECT_LISTEN 50 | value: :8080 51 | - name: AGENT_INJECT_LOG_LEVEL 52 | value: info 53 | - name: AGENT_INJECT_VAULT_ADDR 54 | value: http://vault.default.svc:8200 55 | - name: AGENT_INJECT_VAULT_AUTH_PATH 56 | value: auth/kubernetes 57 | - name: AGENT_INJECT_VAULT_IMAGE 58 | value: "hashicorp/vault:1.8.0" 59 | - name: AGENT_INJECT_TLS_AUTO 60 | value: vault-agent-injector-cfg 61 | - name: AGENT_INJECT_TLS_AUTO_HOSTS 62 | value: vault-agent-injector-svc,vault-agent-injector-svc.default,vault-agent-injector-svc.default.svc 63 | - name: AGENT_INJECT_LOG_FORMAT 64 | value: standard 65 | - name: AGENT_INJECT_REVOKE_ON_SHUTDOWN 66 | value: "false" 67 | - name: AGENT_INJECT_CPU_REQUEST 68 | value: "250m" 69 | - name: AGENT_INJECT_CPU_LIMIT 70 | value: "500m" 71 | - name: AGENT_INJECT_MEM_REQUEST 72 | value: "64Mi" 73 | - name: AGENT_INJECT_MEM_LIMIT 74 | value: "128Mi" 75 | - name: AGENT_INJECT_DEFAULT_TEMPLATE 76 | value: "map" 77 | - name: AGENT_INJECT_TEMPLATE_CONFIG_EXIT_ON_RETRY_FAILURE 78 | value: "true" 79 | 80 | args: 81 | - agent-inject 82 | - 2>&1 83 | livenessProbe: 84 | httpGet: 85 | path: /health/ready 86 | port: 8080 87 | scheme: HTTPS 88 | failureThreshold: 2 89 | initialDelaySeconds: 5 90 | periodSeconds: 2 91 | successThreshold: 1 92 | timeoutSeconds: 5 93 | readinessProbe: 94 | httpGet: 95 | path: /health/ready 96 | port: 8080 97 | scheme: HTTPS 98 | failureThreshold: 2 99 | initialDelaySeconds: 5 100 | periodSeconds: 2 101 | successThreshold: 1 102 | timeoutSeconds: 5 103 | -------------------------------------------------------------------------------- /vault-injector-manifests/mutating-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Source: vault/templates/injector-mutating-webhook.yaml 3 | apiVersion: admissionregistration.k8s.io/v1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: vault-agent-injector-cfg 7 | labels: 8 | app.kubernetes.io/name: vault-agent-injector 9 | app.kubernetes.io/instance: vault 10 | app.kubernetes.io/managed-by: Helm 11 | webhooks: 12 | - name: vault.hashicorp.com 13 | sideEffects: None 14 | admissionReviewVersions: 15 | - "v1beta1" 16 | - "v1" 17 | clientConfig: 18 | service: 19 | name: vault-agent-injector-svc 20 | namespace: default 21 | path: "/mutate" 22 | caBundle: "" 23 | rules: 24 | - operations: ["CREATE", "UPDATE"] 25 | apiGroups: [""] 26 | apiVersions: ["v1"] 27 | resources: ["pods"] 28 | failurePolicy: Ignore 29 | -------------------------------------------------------------------------------- /vault-injector-manifests/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: vault-agent-injector 6 | namespace: default 7 | labels: 8 | app.kubernetes.io/name: vault-agent-injector 9 | app.kubernetes.io/instance: vault 10 | 11 | --- 12 | apiVersion: rbac.authorization.k8s.io/v1 13 | kind: ClusterRole 14 | metadata: 15 | name: vault-agent-injector-clusterrole 16 | labels: 17 | app.kubernetes.io/name: vault-agent-injector 18 | app.kubernetes.io/instance: vault 19 | rules: 20 | - apiGroups: ["admissionregistration.k8s.io"] 21 | resources: ["mutatingwebhookconfigurations"] 22 | verbs: 23 | - "get" 24 | - "list" 25 | - "watch" 26 | - "patch" 27 | 28 | --- 29 | apiVersion: rbac.authorization.k8s.io/v1 30 | kind: ClusterRoleBinding 31 | metadata: 32 | name: vault-agent-injector-binding 33 | labels: 34 | app.kubernetes.io/name: vault-agent-injector 35 | app.kubernetes.io/instance: vault 36 | roleRef: 37 | apiGroup: rbac.authorization.k8s.io 38 | kind: ClusterRole 39 | name: vault-agent-injector-clusterrole 40 | subjects: 41 | - kind: ServiceAccount 42 | name: vault-agent-injector 43 | namespace: default 44 | 45 | -------------------------------------------------------------------------------- /vault-injector-manifests/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: vault-agent-injector-svc 6 | namespace: default 7 | labels: 8 | app.kubernetes.io/name: vault-agent-injector 9 | app.kubernetes.io/instance: vault 10 | spec: 11 | ports: 12 | - name: https 13 | port: 443 14 | targetPort: 8080 15 | selector: 16 | app.kubernetes.io/name: vault-agent-injector 17 | app.kubernetes.io/instance: vault 18 | component: webhook 19 | -------------------------------------------------------------------------------- /vault-manifests/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: vault-config 5 | namespace: default 6 | data: 7 | extraconfig-from-values.hcl: |- 8 | disable_mlock = true 9 | ui = true 10 | 11 | listener "tcp" { 12 | tls_disable = 1 13 | address = "[::]:8200" 14 | cluster_address = "[::]:8201" 15 | } 16 | storage "file" { 17 | path = "/vault/data" 18 | } 19 | -------------------------------------------------------------------------------- /vault-manifests/rbac.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: vault 6 | namespace: default 7 | 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: vault-server-binding 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: ClusterRole 16 | name: system:auth-delegator 17 | subjects: 18 | - kind: ServiceAccount 19 | name: vault 20 | namespace: default 21 | 22 | -------------------------------------------------------------------------------- /vault-manifests/services.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Service for Vault Server 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | name: vault 7 | namespace: default 8 | labels: 9 | app.kubernetes.io/name: vault 10 | app.kubernetes.io/instance: vault 11 | annotations: 12 | spec: 13 | type: NodePort 14 | publishNotReadyAddresses: true 15 | ports: 16 | - name: http 17 | port: 8200 18 | targetPort: 8200 19 | nodePort: 32000 20 | - name: https-internal 21 | port: 8201 22 | targetPort: 8201 23 | selector: 24 | app.kubernetes.io/name: vault 25 | app.kubernetes.io/instance: vault 26 | component: server 27 | 28 | --- 29 | # Headless Service 30 | apiVersion: v1 31 | kind: Service 32 | metadata: 33 | name: vault-internal 34 | namespace: default 35 | labels: 36 | app.kubernetes.io/name: vault 37 | app.kubernetes.io/instance: vault 38 | annotations: 39 | spec: 40 | clusterIP: None 41 | publishNotReadyAddresses: true 42 | ports: 43 | - name: "http" 44 | port: 8200 45 | targetPort: 8200 46 | - name: https-internal 47 | port: 8201 48 | targetPort: 8201 49 | selector: 50 | app.kubernetes.io/name: vault 51 | app.kubernetes.io/instance: vault 52 | component: server 53 | -------------------------------------------------------------------------------- /vault-manifests/statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: vault 5 | namespace: default 6 | labels: 7 | app.kubernetes.io/name: vault 8 | app.kubernetes.io/instance: vault 9 | spec: 10 | serviceName: vault-internal 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: vault 15 | app.kubernetes.io/instance: vault 16 | component: server 17 | template: 18 | metadata: 19 | labels: 20 | app.kubernetes.io/name: vault 21 | app.kubernetes.io/instance: vault 22 | component: server 23 | spec: 24 | serviceAccountName: vault 25 | securityContext: 26 | runAsNonRoot: true 27 | runAsGroup: 1000 28 | runAsUser: 100 29 | fsGroup: 1000 30 | volumes: 31 | - name: config 32 | configMap: 33 | name: vault-config 34 | - name: home 35 | emptyDir: {} 36 | containers: 37 | - name: vault 38 | image: hashicorp/vault:1.18.0 39 | imagePullPolicy: IfNotPresent 40 | command: 41 | - "/bin/sh" 42 | - "-ec" 43 | args: 44 | - | 45 | cp /vault/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; 46 | [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; 47 | [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; 48 | [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; 49 | [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; 50 | [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; 51 | [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; 52 | /usr/local/bin/docker-entrypoint.sh vault server -config=/tmp/storageconfig.hcl 53 | securityContext: 54 | allowPrivilegeEscalation: false 55 | env: 56 | - name: HOSTNAME 57 | valueFrom: 58 | fieldRef: 59 | fieldPath: metadata.name 60 | - name: VAULT_ADDR 61 | value: "http://127.0.0.1:8200" 62 | - name: VAULT_API_ADDR 63 | value: "http://$(POD_IP):8200" 64 | - name: SKIP_CHOWN 65 | value: "true" 66 | - name: SKIP_SETCAP 67 | value: "true" 68 | - name: VAULT_CLUSTER_ADDR 69 | value: "https://$(HOSTNAME).vault-internal:8201" 70 | - name: HOME 71 | value: "/home/vault" 72 | volumeMounts: 73 | - name: data 74 | mountPath: /vault/data 75 | - name: config 76 | mountPath: /vault/config 77 | - name: home 78 | mountPath: /home/vault 79 | ports: 80 | - containerPort: 8200 81 | name: http 82 | - containerPort: 8201 83 | name: https-internal 84 | - containerPort: 8202 85 | name: http-rep 86 | readinessProbe: 87 | exec: 88 | command: ["/bin/sh", "-ec", "vault status -tls-skip-verify"] 89 | failureThreshold: 2 90 | initialDelaySeconds: 5 91 | periodSeconds: 5 92 | successThreshold: 1 93 | timeoutSeconds: 3 94 | volumeClaimTemplates: 95 | - metadata: 96 | name: data 97 | spec: 98 | accessModes: 99 | - ReadWriteOnce 100 | resources: 101 | requests: 102 | storage: 1Gi 103 | --------------------------------------------------------------------------------