# openbao-gitops Deploys [OpenBao](https://openbao.org/) (standalone mode, file storage backend) as the cluster's central secret management backend, and wires up the [External Secrets Operator](https://external-secrets.io/) (ESO) to read from it via Vault's Kubernetes auth method. This chart wraps the official [`openbao-helm`](https://github.com/openbao/openbao-helm) chart as a dependency and adds: - A self-signed TLS certificate (via cert-manager) that OpenBao terminates itself, so both the UI and API are served over HTTPS - A `ClusterSecretStore` (ESO CRD) pointing at the OpenBao service - A one-time bootstrap `Job` (disabled by default) that enables the Kubernetes auth method, a read-only policy, and a role bound to ESO's ServiceAccount ## TLS OpenBao terminates HTTPS itself using a certificate issued by a dedicated `ClusterIssuer/openbao-selfsigned` (cert-manager, `selfSigned` type - no external CA involved). The UI/API is reachable at `https://:30200` (NodePort, same pattern as ArgoCD). Because the certificate is self-signed, browsers will show a trust warning - this is expected. `ExternalSecret`/`ClusterSecretStore` traffic from ESO trusts it automatically via `caProvider` (pointing at the same `openbao-tls` Secret cert-manager creates), so no manual CA import is needed for that path. If you add/replace a node, or want a different reachable hostname, add it to `tls.ipAddresses` / `tls.dnsNames` in `values.yaml` and cert-manager will reissue the certificate automatically. ## Prerequisites - ESO must already be installed in the cluster (deployed separately via the `apps-in-apps` repo) with a ServiceAccount named `eso.serviceAccountName` (default: `external-secrets`) in `eso.namespace` (default: `external-secrets`). - cert-manager must already be installed (used for the self-signed TLS cert, see below). ## Deployment & manual init/unseal OpenBao (like Vault) cannot be auto-initialized/unsealed when using file storage without a KMS auto-unseal mechanism, so this part is a manual, one-time step per environment: 1. Deploy this chart (via ArgoCD, see `apps-in-apps`) - or locally: ```sh helm dependency update . helm upgrade --install openbao . -n openbao --create-namespace ``` 2. Initialize OpenBao (**save the unseal keys and root token securely**, e.g. in a password manager - they are NOT stored anywhere in git): ```sh kubectl exec -n openbao -it openbao-0 -- bao operator init ``` 3. Unseal (repeat with 3 of the 5 unseal keys from step 2): ```sh kubectl exec -n openbao -it openbao-0 -- bao operator unseal ``` 4. Store the root token as a Secret so the bootstrap Job can use it: ```sh kubectl create secret generic openbao-root-token \ -n openbao --from-literal=token= ``` 5. Enable the bootstrap Job and re-sync (e.g. `--set bootstrap.enabled=true` via the ArgoCD Application's Helm parameters, or in `values.yaml`). It enables the KV v2 engine, the Kubernetes auth method, the `eso-read` policy and the `eso-role` role bound to the ESO ServiceAccount. 6. Confirm the `ClusterSecretStore/openbao` becomes `Valid`: ```sh kubectl get clustersecretstore openbao -o wide ``` After this, any namespace can create an `ExternalSecret` referencing the `openbao` `ClusterSecretStore` to pull secrets from OpenBao's `secret/` KV mount. > Note: after a pod restart (upgrade, node reschedule, etc.) OpenBao comes > back up **sealed** and must be unsealed again with the keys from step 2 > unless you later configure an auto-unseal mechanism (e.g. Transit, cloud > KMS) - out of scope for this initial setup. ## Configuration See [`values.yaml`](values.yaml). Key settings: | Key | Description | Default | |---|---|---| | `openbao.server.dataStorage.size` | PVC size for OpenBao's data | `10Gi` | | `openbao.server.dataStorage.storageClass` | StorageClass, empty = cluster default | `""` | | `eso.namespace` / `eso.serviceAccountName` | Where ESO runs and which ServiceAccount to bind | `external-secrets` | | `eso.kvMountPath` | KV v2 mount path used by the ClusterSecretStore | `secret` | | `bootstrap.enabled` | Toggle the one-time auth/policy bootstrap Job | `false` |