search by tags

for the user

adventures into the land of the command line

accessing vault secrets from k8s deployments

here's one way of doing it, which will set your secrets as environment variables in your k8s pods.

install and configure vault

install vault

helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
helm install incubator/vault --set vault.dev=false --set vault.config.storage.consul.address="myconsul-svc-name:8500",vault.config.storage.consul.path="vault"

this cluster role binding should be here

kubectl get clusterrolebinding vault -o yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: vault
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: vault
  namespace: vault

enable and configure the kubernetes auth method

vault auth enable kubernetes

SECRET=$(kubectl get sa vault -n vault -o json | jq -r '.secrets[0].name')
TOKEN=$(kubectl get secret $SECRET -n vault -o json | jq -r '.data.token' | base64 -D)
kubectl get secret $SECRET -n vault -o json | jq -r '.data["ca.crt"]' | base64 -D > ca.crt
vault write auth/kubernetes/config \ 
    token_reviewer_jwt="$TOKEN" \ 
    kubernetes_host=https://KUBERNETES_API_ADDR:443 \ 
    kubernetes_ca_cert=@ca.crt
rm ca.crt

hey! now we can store our secrets there!

add some secrets and set up some access policy

exec into the container

kubectl exec -it `kubectl get pods | awk '{print $1}' | grep vault | head -1` -- /bin/sh

add or edit your secrets

vault kv put kv2/MY_GROOVY_SERVICE MY_GROOVY_SECRET_NAME=MYGROOVYSECRET
vault kv patch kv2/MY_GROOVY_SERVICE ANOTHER_GROOVY_SECRET_NAME=ANOTHERGROOVYSECRET

remember, if your secret contains $ you may need to escape it like

vault kv put kv2/MY_GROOVY_SERVICE SECRET_CONTAINING_DOLLARS=thi\$_\$ecret_i\$_a_\$ecret

list existing secrets in the kv2 backend

vault kv list kv2

add an access policy for your secret

cat <<EOF | vault policy write MY_GROOVY_SERVICE -
path "/kv2/data/MY_GROOVY_SERVICE" {
  capabilities = [ "read" ]
}
EOF

create a kubernetes auth role, and attach your policy to it

vault write auth/kubernetes/role/MY_GROOVY_SERVICE \ 
  bound_service_account_names=MY_GROOVY_SERVICE \ 
  bound_service_account_namespaces=MY_GROOVY_NAMESPACE \ 
  policies=MY_GROOVY_SERVICE \ 
  ttl=1h

setup the vault secrets webhook in k8s

this will let us access our secrets by popping them into our pods as environment variables

git clone https://github.com/innovia/kubernetes-mutation-webhook-vault-secrets.git
helm install helm-chart/

manually add the vault deployment's secret's ca cert as a secret to your deployment's desired namespace:

kubectl get secret $(kubectl get secret | grep vault-token | awk '{print $1}') -o json | jq -r '.data["ca.crt"]' | base64 -D > vault-consul-ca.crt
kubectl create secret generic vault-consul-ca --from-literal=ca.pem="$(cat vault-consul-ca.crt)" -n MY_GROOVY_NAMESPACE

where MY_GROOVY_NAMESPACE is the namespace where you want to deploy your app, not the namespace vault is running in.

now we can use it to read our secrets!

access your secrets from your helm deployment

making sure the name of the service account should match the name of the bound_service_account_names you added above when creating a kubernetes auth role:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: MY_GROOVY_SERVICE <----------- HERE
  labels:
    app: ...
    chart: ...
    heritage: ...
    release: ...
    owner: ...

and in our deployment, make sure we include these annotations, serviceAccountName & envs.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: xxx
  labels:
    app: xxx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: xxx
      annotations:
        vault.security/enabled: "true" <------------------------------------------- So the vault secrets webhook knows to operate on pods in this deployment
        vault.security/vault-addr: "http://VAULT_SERVICE_OR_INGRESS_ADDR:8200" <--- So it knows where to find vault
        vault.security/vault-role: "MY_GROOVY_SERVICE" <--------------------------- So it knows which kubernetes vault auth role to use
        vault.security/vault-path: "/kv2/data/MY_GROOVY_SERVICE" <----------------- So it knows where to find your secrets
        vault.security/vault-tls-secret-name: "vault-consul-ca" <------------------ This is the name of the manually created secret, vault-consul-ca, we did earlier.
    spec:
      serviceAccountName: MY_GROOVY_SERVICE <-------------------------------------- The service account with kubernetes vault auth role permissions
      containers:
      - name: xxx
        image: {{ $.Values.image.repository }}:{{ $.Values.image.tag }}
        command:
          - "java"
          - "-jar"
          - "/app/application.jar"
          - "-Do=it"
        env:
        - name: "MY_GROOVY_SECRET" <---------------------------------------------- So it knows the name of the env var to store the secret in
          value: "vault:MY_GROOVY_SECRET" <--------------------------------------- So it knows what this secret is named in vault. This is the most important bit!

et voilà. now you can read these secrets from you application, simply by reading the environment variable.

Cookies

We use third-party cookies to analyse web traffic.

Read more.