Ultimate DevSecOps Bootcamp by School of Devops: Secrets Management with Vault


Делаю:
2026.01.04


Устанавливаю vault


// Connect to the vault-0 which has the vault manager configured
$ kubectl exec -it -n vault vault-0 -- sh


// Explore vault using some simple commands
$ vault
$ vault status
$ vault secrets list


// Adding Secret to the Vault
$ vault kv put secret/dso-demo/database username=devops password=mysupersecret


// Retrieve information that you just added and verify
$ vault kv list secret/
$ vault kv list secret/dso-demo
$ vault kv get secret/dso-demo/database


======== Secret Path ========
secret/data/dso-demo/database

======= Metadata =======
Key                Value
---                -----
created_time       2026-01-04T05:26:07.408297829Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
password    mysupersecret
username    devops


Setting up Vault Access Policies


$ vault policy
$ vault policy list


$ vault policy write dso-demo - <<EOF
path "secret/data/dso-demo/database" {
capabilities = ["read"]
}
EOF


$ vault policy read dso-demo
path "secret/data/dso-demo/database" {
capabilities = ["read"]


Writing Policy and Kubernetes RBAC

$ vault auth
$ vault auth list


$ vault auth enable kubernetes
$ vault auth list


$ env | grep -i kube
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1


$ ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt     namespace  token


$ ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt     namespace  token


$ vault write auth/kubernetes/config \
    kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
    token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    issuer="https://kubernetes.default.svc.cluster.local"


$ vault auth list
Path           Type          Accessor                    Description                Version
----           ----          --------                    -----------                -------
kubernetes/    kubernetes    auth_kubernetes_6ca9cb88    n/a                        n/a
token/         token         auth_token_1081d226         token based credentials    n/a


// map the vault policy with the service
account dso-demo
$ vault write auth/kubernetes/role/dso-demo \
    bound_service_account_names=dso-demo \
    bound_service_account_namespaces=default \
    policies=dso-demo \
    audience="" \
    ttl=30h


Injecting a Secret into the Pod


Нужно добавить serviceAccountName: dso-demo и:

annotations:
    vault.hashicorp.com/agent-inject: 'true'
    vault.hashicorp.com/role: 'dso-demo'
    vault.hashicorp.com/agent-inject-secret-database: 'secret/dso-demo/database'

В файл:

https://github.com/wildmakaka/dso-demo/blob/main/deploy/dso-demo-deploy.yaml


$ cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dso-demo
EOF


$ cat << 'EOF' | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: dso-demo
  name: dso-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dso-demo
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: dso-demo
      annotations:
        vault.hashicorp.com/agent-inject: 'true'
        vault.hashicorp.com/role: 'dso-demo'
        vault.hashicorp.com/agent-inject-secret-database: 'secret/dso-demo/database'
    spec:
      serviceAccountName: dso-demo
      containers:
        - image: webmakaka/dso-demo
          name: dso-demo
          ports:
            - containerPort: 8080
          resources: {}
status: {}
EOF


$ kubectl get pods
NAME                        READY   STATUS     RESTARTS   AGE
dso-demo-6768c4d85f-chrwk   0/2     Init:0/1   0          2m4s


Пошли траблшутить!


Troubleshooting the Vault Policy

$ vault policy read dso-demo
path "secret/data/dso-demo/database" {
capabilities = ["read"]


$ vault kv get secret/dso-demo/database
======== Secret Path ========
secret/data/dso-demo/database

======= Metadata =======
Key                Value
---                -----
created_time       2026-01-04T05:26:07.408297829Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
password    mysupersecret
username    devops


$ vault policy write dso-demo - <<EOF
path "secret/data/dso-demo/*" {
capabilities = ["read"]
}
EOF


$ vault policy read dso-demo
path "secret/data/dso-demo/*" {
capabilities = ["read"]
}


Не помогло!


$ vault policy write dso-demo - <<EOF
path "*" {
capabilities = ["read"]
}
EOF


$ kubectl exec -it dso-demo-xxxx -- sh


# ls /vault/secrets/
database


# cat /vault/secrets/database
data: map[password:mysupersecret username:devops]
metadata: map[created_time:2026-01-04T05:26:07.408297829Z custom_metadata:<nil> deletion_time: destroyed:false version:1]


$ vault policy write dso-demo - <<EOF
path "secret/data/dso-demo/database" {
capabilities = ["read"]
}
EOF


Customizing Secrets using Templates


$ cat << 'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: dso-demo
  name: dso-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dso-demo
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: dso-demo
      annotations:
        vault.hashicorp.com/agent-inject: 'true'
        vault.hashicorp.com/role: 'dso-demo'
        vault.hashicorp.com/agent-inject-secret-database: 'secret/dso-demo/database'
        vault.hashicorp.com/agent-inject-template-database: |mysql -u  -p  -h database:3306 mydbspec:
      serviceAccountName: dso-demo
      containers:
        - image: webmakaka/dso-demo
          name: dso-demo
          ports:
            - containerPort: 8080
          resources: {}
status: {}
EOF


$ kubectl exec -it dso-demo-xxxx -- sh


# cat /vault/secrets/database
mysql -u devops -p mysupersecret -h database:3306 mydb


Rotating Secrets

$ vault kv put secret/dso-demo/database user=devops password=superdupersecretnow


Ждем сколько-то времени.


# cat /vault/secrets/database
mysql -u <no value> -p superdupersecretnow -h database:3306 mydb