Repository navigation
fix(openbao): issue the listener certificate from a CA and trust the CA - #145
Conversation
OpenBao's listener certificate came from a self-signed issuer, so the certificate was its own trust anchor. Every reissue changed what ESO, the object-storage stores and the in-pod CLI trusted, and they failed TLS until someone restarted the pods and refreshed the stores by hand. Issue the certificate from a CA that lives with OpenBao in its namespace (a self-signed root that keeps its key on renewal, and a CA Issuer backed by it), and point every client at the CA: - ESO and the object-storage stores take the CA's own certificate. A missing CA stops those plays with a pointer to the cert-manager play, unless external trust is set explicitly. - The pods trust ca.crt (BAO_CACERT, leader_ca_cert_file). - The issuance waits prove the new issuance: current generation, the CA Issuer's annotations, and the leaf verifying against the current CA. - After each issuance, the cert-manager play reloads every running pod's listener (SIGHUP) and checks over the pod address that it serves the new leaf, so a renewal reaches the servers without a restart and an existing env migrates without a stranded pod. - The openbao role stops on an unreadable status instead of treating it as not initialized. The role READMEs describe the new behaviour and variables. The operator procedure is the umbrella runbook docs/runbooks/openbao-listener-certificate.md. Closes dmfdeploy/dmfdeploy#879 Signed-off-by: znerol2 <6800371+znerol2@users.noreply.github.com>
The playbook tests run one after another against fakes. With the OpenBao certificate tests added, the job runs past its 15-minute limit and is cancelled before it finishes. Allow 30 minutes. Refs dmfdeploy/dmfdeploy#879 Signed-off-by: znerol2 <6800371+znerol2@users.noreply.github.com>
lkirc
left a comment
There was a problem hiding this comment.
Request changes: the migration/recovery instructions rely on a runbook that is unavailable at the linked URL.
- docs/openbao-bootstrap-security-model.md:480 — The
main-branch link currently returns 404; its companion dmfdeploy/dmfdeploy#904 is still open. Merge/publish that runbook before this PR, or include/link to a currently available complete procedure, so operators can safely perform the ordered migration and recovery.
|
Agreed: the runbook has to be on |
|
dmfdeploy/dmfdeploy#904 has merged, so the runbook link in this PR now resolves (HTTP 200 on main). The head is unchanged at fadf731, and all checks pass. Ready for another look. |
lkirc
left a comment
There was a problem hiding this comment.
Approved. The companion runbook that prompted the earlier request now resolves on main, and the current head coherently moves clients to the CA trust anchor while proving issuance and listener reload. Required checks and the precise ntfy OK token are present.
What this changes
OpenBao's listener certificate came from a self-signed issuer, so the certificate was its own trust anchor. Every reissue, on renewal or when the names change, changed what clients trusted. ESO went
InvalidProviderConfig, and the in-podbaoCLI failed with "certificate signed by unknown authority", until the pods restarted and the stores were refreshed by hand.The certificate now comes from a CA that lives with OpenBao in its namespace, and every client trusts the CA:
openbao-ca(10 years, renewed a year early,rotationPolicy: Neverso a renewed root keeps its key) and a CA Issuer that signs theopenbaoleaf. The leaf Certificate and Secret keep their names.BAO_CACERTandleader_ca_cert_filepoint atca.crt.SIGHUP, and compares the certificate the pod serves, read over the pod's cluster address, with the new leaf. A renewal then takes effect without a restart, and an existing env migrates without stranding a pod.bao status. It no longer treats a failed read as "not initialized".320-cert-manager.yml, unless external trust is set explicitly (eso_openbao_external_trust,object_storage_eso_openbao_external_trust).The role READMEs describe the new behaviour and variables. The operator procedure (migration, routine renewal, CA renewal) is a new umbrella runbook,
docs/runbooks/openbao-listener-certificate.md, in a companion PR.Tests
test-openbao-cert-issuance.yml(migration, renewal, a server that ignores the signal, stale and old-generation issuances, late and missing projection),test-openbao-ca-bundle.yml(the real ESO and object-storage tasks, reading thecaBundleeach store gets),test-openbao-init-status.yml, andtest-openbao-tls-secret-wait.yml. A new unit test covers the static wiring. All run in CI.Live run (sandbox env, three Raft pods)
320-cert-manager.yml: CA created, leaf reissued and proven, each pod reloaded, and every pod's own CLI kept working. Until step 2, the ESO store wasInvalidProviderConfig, as expected.vertical-orchestration/100-eso.yml: the store wasValidagain and every ExternalSecret was synced.vertical-security/100-openbao.yml: new pod spec applied. Nothing ran init.vertical-security/103-openbao-restart-pod.ymlfor each pod, standbys first and the leader last, unsealed from the automation file: every pod onBAO_CACERT=.../ca.crt, unsealed, at the same Raft index.320-cert-manager.ymlagain: every pod served the renewed leaf (fingerprint compared over the pod address), with no restart. The CLI worked, the store stayedValidwithout the ESO play, and a forced ExternalSecret sync succeeded.Object storage is off on that env, so the object-storage play didn't run.
Known limit and follow-ups
OpenBao 2.5.2 has no
tls_auto_reload, so a renewed leaf reaches the servers when320-cert-manager.ymlnext runs, within the renewal window. dmfdeploy/dmfdeploy#902 upgrades OpenBao to 2.7.x, which reloads the certificate by itself. dmfdeploy/dmfdeploy#903 pins platform images by digest.The companion dmf-env PR updates the TLS error text in
bin/unseal-openbao.sh.Closes dmfdeploy/dmfdeploy#879