From 58d16315fb8862f8b04d43414d5c9b848c73aaba Mon Sep 17 00:00:00 2001 From: Alex Lebens Date: Sun, 19 Apr 2026 17:42:18 -0500 Subject: [PATCH] feat: add doc for secret store --- src/content/docs/guides/secret-store-csi.mdx | 76 ++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/content/docs/guides/secret-store-csi.mdx diff --git a/src/content/docs/guides/secret-store-csi.mdx b/src/content/docs/guides/secret-store-csi.mdx new file mode 100644 index 0000000..2953bfb --- /dev/null +++ b/src/content/docs/guides/secret-store-csi.mdx @@ -0,0 +1,76 @@ +--- +title: Using Secret Store CSI with OpenBao +description: Mounting secrets inside pods using Secret Store CSI driver and OpenBao +hero: + tagline: Steps followed to mount the secrets + image: + file: https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/openbao.webp +--- + +This guide assumes both Secrets Store CSI and OpenBao are installed and working. Also, the Kubernetes auth method is enabled. I wrote a post [here](https://www.alexlebens.dev/blog/openbao-migration/) that detailed my steps to set these up. + +NOTE: A catch I found is that the mount directory should be empty. There are issues when mounting a specific file into a directory that is already populated. For common uses, such as config files, use an env variable to change that path. + +The following will be needed per namespace, with the SecretProviderClass per secret to mount. + +## Secret Provider Class + +This template is used to create the volume and retrieve the secret from OpenBao. Some notes: +- The provider is 'openbao' and the address should point to the internal service. +- The roleName referenced here is created in the next step. +- secretPath should include the secret store and data if its a v2 kv engine. +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: web-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: web-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + provider: openbao + parameters: + baoAddress: "http://openbao-internal.openbao:8200" + roleName: web + objects: | + - objectName: config.yaml + secretPath: secret/data/web/config + secretKey: config.yaml +``` + +## Role + +In the namespace where this secret is getting mounted there should be a ServiceAccount that will be use the role to retrieve the secret. This should also be the one used by the pod. It only needs read access to the secret path and I have created a policy called 'reader' for this. + +Each ServiceAccount will need a role created. +```bash +bao write auth/kubernetes/role/web \ + bound_service_account_names=web \ + bound_service_account_namespaces=web \ + policies=reader \ + ttl=20m +``` + +## Mount + +When using the [app-template](https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template) common chart the following is how to mount the secret. This needs to use the custom type to define the spec. secretProviderClass references the above template. Use the advancedMounts to specify the path for the file. +```yaml +persistence: + web-config: + type: custom + volumeSpec: + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: web-config-secret + advancedMounts: + main: + main: + - path: /config/config.yaml + readOnly: true + mountPropagation: None + subPath: config.yaml +``` \ No newline at end of file