Files
cozystack/packages/apps
Aleksei Sviridkin 6f49e5f427 feat(openbao): optional static-key auto-unseal and apiserver egress label (#4766)
## What this PR does

This continues #4168 by @txmazing, which has been idle since 2026-09-10.
The first commit is the work from #4168 squashed into one, with
@txmazing as author. The other two commits constrain the new values and
complete the documentation.

Five changes to the managed OpenBAO app (`packages/apps/openbao`).

1. **Optional static-key auto-unseal** (#2787, #2483). `seal.type` is
`shamir`, the unchanged default, or `static`. With `static` the chart
mounts the Secret named in `seal.secretName` through the upstream
chart's `server.extraVolumes` and adds OpenBAO's `seal "static"` stanza
to the standalone and the Raft config, so the pods unseal themselves
after a restart. `seal.previousSecretName` and `seal.previousKeyId`
carry the n-1 key during a rotation. The chart never generates the key.
A cluster administrator creates the Secret in the tenant namespace,
because the `cozy:tenant:*` roles grant nothing on Secrets. A way for
tenants to supply secrets by reference is proposed separately in
cozystack/community#82.
2. **No silent seal change.** The template reads the seal in use from
the `<release>-config` ConfigMap and refuses a different `seal.type`
unless `seal.allowMigration: true` acknowledges a migration. Going from
`static` back to `shamir` is refused, because the chart cannot render
the disabled stanza that direction needs.
3. **Apiserver egress label** (#2793). The server pods carry
`policy.cozystack.io/allow-to-apiserver: "true"`, so
`service_registration "kubernetes"` reaches the API server and HA pods
no longer hang at start.
4. **Constrained values.** The upstream chart passes the server config
through `tpl`, and its start script replaces upper case placeholders
such as `HOSTNAME` in it. A key identifier with template delimiters
would run as a template inside helm-controller, which runs as
cluster-admin, so `seal.keyId` and `seal.previousKeyId` take lowercase
alphanumerics, hyphens, dots and underscores. The Secret names become
pod volume names `userconfig-<name>`, so they take DNS labels of at most
52 characters. A previous Secret or key identifier equal to the current
one fails at render. The apps API only defaults against the schema, and
Helm enforces these patterns at install and upgrade.
5. **README.** The trade-off of `static`, the key Secret, the rotation
with the pod replacement that the `OnDelete` strategy requires, the
migration from Shamir step by step after the OpenBAO guide, and the
one-time pod replacement after an upgrade so that existing pods get the
label.

### Validation

- `helm unittest .` in `packages/apps/openbao` passes 28 of 28 with
helm-unittest 1.1.2, the version CI pins, and with 1.2.1.
- Dropping the key identifier patterns, moving the Secret name limit to
51 or 53, or removing either equality guard turns the suite red each
time.
- Rendering this chart and then the vendored `openbao` chart with a
template in `seal.keyId` now stops at the schema. Without the pattern
the same two-stage render executed it, `lookup` included.
- With default values, standalone and with `replicas: 3`, `helm
template` renders the same as `main` apart from the six-line
`extraLabels` block.
- `make generate` in the package with cozyvalues-gen v1.7.0 and at the
repository root with Go 1.27.1 leaves the tree unchanged. `make
unit-tests` passes apart from seven BATS tests that fail the same way on
a clean `main` under macOS, most of them because macOS ships no
`timeout`. In `make test-controllers` only `internal/backupcontroller`
fails, because its tests do not build on current `main` either, which
#4768 fixes. `hack/check-commit-trailers.sh` passes and `cmd/api-gate`
reports no sizeable API change.
- Nothing here was run on a cluster. #4168 reports a Cozystack v1.6.3
cluster where a `replicas: 1` instance with `seal.type: static` came
back `Sealed false` after `kubectl delete pod`.

TLS between pods and an init or bootstrap job are not covered. Both are
on the #2787 list and independent of this change.

### Screenshots

No dashboard code change. The application form gains the `seal` group
from the regenerated `openAPISchema` and `keysOrder`.

### Downstream repositories

Walked the trigger map against the diff. The new `seal` field in
`packages/apps/openbao/values.schema.json` reaches the hand-written
`cozystack_openbao` resource of the Terraform provider. That is tracked
in cozystack/terraform-provider-cozystack#44, which also needs
`allowMigration` and the value constraints. The website reference page
is generated from this `README.md` for the apps listed in its
`Makefile`, and `openbao` is in `APPS`, so the page follows the next
stable tag without a follow-up. The website pages that mention the
apiserver label describe it in general terms and carry no OpenBAO
workaround. There is no `hack/` change, no platform values change, no
variant and no change to ApplicationDefinition semantics.

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [x]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
https://github.com/cozystack/terraform-provider-cozystack/issues/44
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
feat(openbao): the OpenBAO app can auto-unseal with OpenBAO's static-key seal (`seal.type: static`) from a Secret that a cluster administrator creates in the tenant namespace, with n-1 rotation through `seal.previousSecretName` and `seal.previousKeyId`. Shamir stays the default, and changing the seal of an existing instance needs `seal.allowMigration`. Server pods now carry `policy.cozystack.io/allow-to-apiserver: "true"`, so HA instances no longer hang at start behind the apiserver egress policy.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* OpenBAO supports static sealing with keys stored in an existing
Secret; Shamir sealing remains the default.
* Configure current and previous keys to support key rotation in
standalone and high-availability deployments. Keep the previous key
until stored keys have been re-wrapped.
* Seal-type changes are validated. Shamir-to-static migration requires
explicit acknowledgement; static-to-Shamir migration is not supported.
* Static-seal settings validate required key details and Secret names.
Server pods receive a label needed by the configured API-server egress
policy.
* **Documentation**
* Added guidance for configuring static sealing, managing Secrets,
rotating keys, and migrating seal types.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-09 02:17:21 +03:00
..
2025-08-07 14:07:05 +03:00

How to test packages local

cd packages/core/installer
make image-cozystack REGISTRY=YOUR_CUSTOM_REGISTRY
make apply
kubectl delete po -l app=source-controller -n cozy-fluxcd