Kubernetes Secrets from Vault
Using Secrets Store CSI Driver
Firstly, storing secrets in Git has been a challenging and every company come up with their own solution of storing secrets and some of them may be SOPS, AWS KMS, Azure KeyVault, Hashicorp Vault.
Here, we will see how we create a Kubernetes Secret(s) from Hashicorp Vault.
Using Vault, we can store all secrets in one location providing enhanced security, auditing capabilities. Secrets Store CSI Driver allows you to access secrets stored within a Vault via the SecretProviderClass custom resource.
In short lets see the steps involved in the workflow:
- SecretProviderClass resource defines the secret provider (Vault) and the secrets to be retrieved.
- Vault Provider Component then uses the SecretProviderClass and the Pods service account in order to retrieve secrets from Vault and then mount them to Pod’s CSI Volume.
- Secrets are mounted, into your Pod, when containers are created.
Prerequisites
- The cluster needs to be setup and the namespace your application resides in need to be setup.
- Cluster/Namespace needs to be setup to allow authentication with vault.
- Application running and the service account within that namespace attached to your application needs to be attached to a Vault Role that gives you access to the secret paths where your secrets are stored.
Method#1 — SPC — Sync
A detailed explanation, on this method, to retrieve secrets from Secret Provider is explained HERE but for simplicity lets understand how this can be done practically.
In this method, we need to define a SecretProviderClass, but lets understand in detail from the below manifest:
cat > spc-vault-sync.yaml <<EOF
---
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: sample-secret
spec:
provider: vault
parameters:
vaultAddress: https://vault.example.com
vaultSkipTLSVerify: 'true'
roleName: my-vault-role # This is the role created at vault
vaultKubernetesMountPath: my-cluster # Path where the k8s authentication backend is mounted in Vault
objects: |
- secretPath: "data/common-secret"
objectName: "secrets1" # symbolic name for that secret, and the file name to write to
secretKey: "key-1"
- secretPath: "data/common-secret"
objectName: "secrets2" # symbolic name for that secret, and the file name to write to
secretKey: "key-1"
EOF
After defining your SecretProviderClass, you will now be able to access secrets from within your pod as below:
cat > pod-vault-sync.yaml <<EOF
---
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
serviceAccountName: my-cluster-svc-acc
containers:
- image: jweissig/app:0.0.1
name: webapp
volumeMounts:
- name: secrets-store-file
mountPath: "/tmp/secrets-store"
readOnly: true
volumes:
- name: secrets-store-file
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "sample-secret"
EOF
The secrets will only sync once you start a pod mounting the secrets.
When all the pods consuming the secret are deleted, the Kubernetes secret is also deleted.
Method#2 — SPC — as ENV
A detailed explanation, on this method, to retrieve secrets from Secret Provider is explained HERE but for simplicity lets understand how this can be done practically.
In this method, we need to define a SecretProviderClass, but lets understand in detail from the below manifest:
cat > spc-vault-env.yaml <<EOF
---
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: sample-secret
spec:
provider: vault
parameters:
vaultAddress: https://vault.example.com
vaultSkipTLSVerify: 'true'
roleName: my-vault-role # This is the role created at vault
vaultKubernetesMountPath: my-cluster # Path where the k8s authentication backend is mounted in Vault
objects: |
- secretPath: "data/common-secret"
objectName: "secrets1" # symbolic name for that secret, and the file name to write to
secretKey: "key-1"
- secretPath: "data/common-secret"
objectName: "secrets2" # symbolic name for that secret, and the file name to write to
secretKey: "key-1"
secretObjects: # Converts from mounted file to Native K8s Secret
- secretName: vault-secrets-example
type: Opaque # Other supported are kubernetes.io/basic-auth, bootstrap.kubernetes.io/token, kubernetes.io/dockerconfigjson, kubernetes.io/dockercfg, kubernetes.io/ssh-auth, kubernetes.io/service-account-token, kubernetes.io/tls
data:
- objectName: secrets1
key: secrets1 # Key within k8s secret for this value
- objectName: secrets2
key: secrets2 # Key within k8s secret for this valu
EOF
After defining your SecretProviderClass, you will now be able to access secrets from within your pod as below:
cat > spc-vault-env.yaml <<EOF
---
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
serviceAccountName: my-cluster-svc-acc
containers:
- image: jweissig/app:0.0.1
name: webapp
envFrom:
- secretRef:
name: vault-secrets-example
volumeMounts:
- name: secrets-store-env
mountPath: "/tmp/secrets-store"
readOnly: true
volumes:
- name: secrets-store-env
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "sample-secret"
EOF