vault kubernetes with csi - juancamilocc/virtual_resources GitHub Wiki

Vault in Kubernetes cluster with CSI plugin

In this guide, you will learn how to set up and deploy Vault step by step in a Kubernetes environment using the CSI plugin.

Installation

First, we need to execute the following commands.

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm install vault hashicorp/vault --namespace vault \
--set server.ha.enabled=false \
--set server.ha.raft.enabled=true \
--set server.ha.raft.storage.storageClass=standard \
--set server.ha.raft.storage.size=10Gi \
--set "injector.enabled=false" \
--set "csi.enabled=true"
kubectl -n vault get pods 
# NAME                       READY   STATUS    RESTARTS   AGE
# vault-0                    0/1     Running   0          2m25s
# vault-csi-provider-69szd   2/2     Running   0          2m25s

Now, we have to get the unseal and root keys.

kubectl exec vault-0 -n vault -- vault operator init -key-shares=1 -key-threshold=1 -format=json > vault-cluster-keys.json
cat vault-cluster-keys.json
# {
#   "unseal_keys_b64": [
#     "<base64 unseal_key>"
#   ],
#   "unseal_keys_hex": [
#     "<hex unseal key>"
#   ],
#   "unseal_shares": 1,
#   "unseal_threshold": 1,
#   "recovery_keys_b64": [],
#   "recovery_keys_hex": [],
#   "recovery_keys_shares": 0,
#   "recovery_keys_threshold": 0,
#   "root_token": "hvs.<token root>"
# }

NOTE: You can generate more than one unseal key by modifying the value of -key-shares, meanwhile the value of -key-threshold specifies how many valid keys are required to unseal Vault. In this guide, for simplicity, we will use only one key.

Now, let's unseal Vault as follows.

kubectl exec vault-0 -n vault -- vault operator unseal <BASE64_UNSEAL_KEY>
# Key                     Value
# ---                     -----
# Seal Type               shamir
# Initialized             true
# Sealed                  false
# Total Shares            1
# Threshold               1
# Version                 1.18.1
# Build Date              2024-10-29T14:21:31Z
# Storage Type            raft
# Cluster Name            vault-cluster-62b0352c
# Cluster ID              6d9984e4-7464-ce94-1b05-523918ca0c73
# HA Enabled              true
# HA Cluster              n/a
# HA Mode                 standby
# Active Node Address     <none>
# Raft Committed Index    33
# Raft Applied Index      33

NOTE: If you generated more than one unseal key, you must repeat the command for each key you have.

Now, let's enable authentication with Kubernetes.

kubectl config view --raw --minify --flatten -o json | jq -r '.clusters[0].cluster.server'
# https://192.168.49.2:8443
kubectl -n vault exec vault-0 -- vault auth enable kubernetes
kubectl -n vault exec vault-0 -- vault write auth/kubernetes/config kubernetes_host=https://192.168.49.2:8443

Now, we need to install the CSI plugin in our Kubernetes cluster.

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver --set syncSecret.enabled=true --namespace kube-system
kubectl --namespace=kube-system get pods -l "app=secrets-store-csi-driver"
# NAME                                               READY   STATUS    RESTARTS       AGE
# csi-secrets-store-secrets-store-csi-driver-fvhr8   3/3     Running   1 (6m1s ago)   7m6s

Finally, we will set up a port-forward to access its graphical interface.

kubectl -n vault port-forward svc/vault 8200:8200

Vault Interface

Access it using the root token generated in our vault-cluster-key.json file.

Vault Interface

Setting up our environment variables

Let’s enable our secrets engine by navigating to Enable a secrets engine > KV > Enable Engine. Here, we will create our first secrets.

Vault Interface

As an example, we will create the following secrets, click on Create secret, set a name and we assign keys and values.

Vault Interface

As an example, we will create the following secrets. Click on Create secret, provide a name, and assign keys and values.

# Allow capabilities in path
path "kv/data/secrets-test/*" {
    capabilities = ["read", "create", "update", "delete"]
}

# Block any action in sys and auth, to avoid administration operations
path "sys/*" {
    capabilities = []
}

path "auth/*" {
    capabilities = []
}

The previous policy allows us to create, read, update, and delete any secrets in the secrets-test path. Additionally, it denies access to auth and sys capabilities.

Vault Interface

We need to create a role. Go to Kubernetes > Create role, and provide a name, in Bound service account name reference a service account that we will use to authenticate against Vault, which is secrets-test. Select the namesppace where our application will be running, which is default. Finally, in Generated Token's Policies, select the policy we created previously, named secrets-test-policy.

Vault Interface Vault Interface

In our Kubernetes cluster, let's create a service account, as follows.

kubectl -n default create serviceaccount secrets-test
kubectl get sa
# NAME                   SECRETS   AGE
# default                0         74d
# secrets-test           0         6s

Now, let's deploy the SecretProviderClass making reference to our secrets.

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: vault-test
  namespace: default
spec:
  provider: vault
  secretObjects:
  - data:
    - objectName: key1 
      key: key1
    - objectName: key2
      key: key2
    secretName: test-secrets 
    type: Opaque
  parameters:
    vaultAddress: "http://vault.vault.svc.cluster.local:8200"
    roleName: "secrets-test-role"
    objects: |
      - objectName: "key1" 
        secretPath: "kv/data/secrets-test"
        secretKey: "key1"
      
      - objectName: "key2"
        secretPath: "kv/data/secrets-test"
        secretKey: "key2"

Verify the secret provider class had been created correctly.

kubectl apply -f secrets-vault.yaml
kubectl -n default get secretproviderclass
# NAME         AGE
# vault-test   34s

Deploy our application and verify the environment variables

Now, let's deploy an application referencing those secrets, as follows.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deploy
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: debian
  template:
    metadata:
      labels:
        app: debian
    spec:
      serviceAccountName: secrets-test
      containers:
      - name: debian
        image: debian:bullseye-slim
        command: ["sleep", "infinity"]
        env:
        - name: key1
          valueFrom:
            secretKeyRef:
              name: test-secrets
              key: key1
        - name: key2
          valueFrom:
            secretKeyRef:
              name: test-secrets
              key: key2
        resources:
          limits:
            cpu: 15m
            memory: 105M
          requests:
            cpu: 15m
            memory: 105M
        volumeMounts:
          - name: test-secrets
            mountPath: "/mnt/secrets-store"
      volumes:
      - name: test-secrets
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
          volumeAttributes:
            secretProviderClass: "vault-test"

We can verify the environment variables in our pod, as follows.

kubectl get pods
# NAME                         READY   STATUS    RESTARTS   AGE
# test-deploy-b9584967-n4xh7   1/1     Running   0          1m13s

kubectl exec -it test-deploy-b9584967-n4xh7 -- bash
# root@test-deploy-b9584967-n4xh7:/# cd mnt/secrets-store/
# root@test-deploy-b9584967-n4xh7:/mnt/secrets-store# ls
# key1  key2

root@test-deploy-b9584967-n4xh7:/# cd mnt/secrets-store# cat key1
# secret1

root@test-deploy-b9584967-n4xh7:/# cd mnt/secrets-store# cat key2
# secret2

root@test-deploy-b9584967-n4xh7:/# cd mnt/secrets-store# echo "$key1"
# secret1

root@test-deploy-b9584967-n4xh7:/# cd mnt/secrets-store# echo "$key2"
# secret2

Conclusion

This guide provides a comprehensive step-by-step procedure to install and configure Vault in a Kubernetes environment using the CSI plugin. It covers all the necessary steps, from installation and initialization to deploying an application that uses Vault-managed secrets.

⚠️ **GitHub.com Fallback** ⚠️