OpenBao 2.7 removed the builtin LDAP auth engine from the server binary
(openbao/openbao GH-3882). `bao auth enable ldap` answered
"plugin not found in the catalog: ldap" and the deploy stopped there.
The role now builds its own image. A multi-stage Dockerfile copies the
openbao-plugin-auth-ldap binary out of the image declared as the
`auth-ldap` service entry into /opt/openbao/plugins. A second server
config file, plugins.hcl, names that directory and registers the plugin
declaratively. It sets plugin_auto_register = true explicitly: the image
starts the server with a config directory, and on that path 2.7.1 does
not apply the documented default, so without the line the catalog stays
empty. The Dockerfile sets the file mode in a helper stage instead of
COPY --chmod, which only BuildKit accepts.
The mount is enabled with -plugin-version=latest, so it follows whichever
plugin version the image ships. A mount created by the former builtin
engine is tuned and reloaded onto the plugin, which needs `update` on
sys/plugins/reload/backend in the ansible-admin policy.
The LDAP tasks move into tasks/addons/auth-ldap.yml and the plugin is
declared under meta/addons as a required addon bridged to `ldap`. Its
Playwright spec logs in through the mount and asserts that sys/auth
reports an external running plugin version.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review had these removed across the role once already, and the 11 September
pass cleared every file that was flagged. The seal-key pin and the
recovery-key work then reintroduced the same pattern in nine new places.
Also removes two that predate the review and were never flagged: the
healthcheck note in meta/services.yml and the entrypoint note in
compose.yml.j2. Both are the same narrative-exception shape.
Param docs, file headers and the plain contract notes in the Playwright specs
stay: separate categories, none of them objected to. What the deleted
comments recorded lives in the role README.
DIR_SECRETS is the durable home a role actually has. The inventory would be
the natural one, but no role writes host_vars -- the CLI writes it before the
play. DIR_SECRETS outlives MODE_RESET and a replaced swarm manager, both of
which take .applied.json with them, and svc-bkp-secrets-2-local backs it up.
The rationale rested on the key rotating every deploy, which it no longer
does. Deriving the id from the key is what keeps it in step with the key,
however rarely that happens.
The platform regenerates generated-algorithm credentials on every deploy, so
the seal key and AppRole this role is handed are not the ones the running
instance holds. Derive current_key_id from the key itself -- upstream requires
the identifier to match its key, and a derived id cannot drift out of step with
one. Carry the previously applied credentials and the two rotation predicates
alongside it, so the config render and the AppRole swap can both tell a
rotation from a steady state.