Request icon
OutputValues icon
Labels icon
If icon
Log icon
Exit icon
Query icon
Pause icon
Assert icon
Commands icon
Docker icon
Webhook icon

Rotate a leaked Postgres password with OpenBao after approval, and prove the old one is dead

Confirm a leaked Postgres password is live, approve, rotate it with OpenBao, end its sessions, and prove the new password works and the old one fails.

Categories
Infrastructure

When a scanner finds a database password in a commit, rotating it is only half of the response: sessions opened with the leaked password stay connected after the password changes, and you want proof that the leaked value no longer works. This flow takes the finding as a SHA-512 fingerprint, checks it against the live password of an OpenBao static role, shows the sessions that use it, and after approval rotates the password through OpenBao's database secrets engine, ends those sessions, and tests the new and the old password against Postgres.

This blueprint was created by kruxarth.

How it works

  1. on_leak (Webhook) receives {"role", "sha512", "source", "location"} from the scanner job. The secret itself never reaches Kestra. Calls without a role name and a 128-character hex fingerprint get a 204 and start nothing.
  2. read_current (http.Request with encryptBody) reads the role's credentials from OpenBao, and current compares the SHA-512 of the live password with the fingerprint.
  3. No match: the leaked value is not the current password. The execution ends with outcome: not-current and changes nothing.
  4. Match: sessions (PostgreSQL Query) lists the user's sessions from pg_stat_activity, show_leak logs them, and approve (Pause) waits for ROTATE_AND_TERMINATE, ROTATE or REJECT, and a note. REJECT ends in WARNING; no answer within approval_window (1 day) fails the execution.
  5. rotate calls OpenBao's rotate-role, and verify_rotation (Assert) requires a new last_vault_rotation and a different password.
  6. ROTATE_AND_TERMINATE: terminate runs pg_terminate_backend on every session of the user that started before the rotation.
  7. new_login logs in with the new password, old_login runs psql with the leaked one and passes only on "password authentication failed", and verify_logins checks that no session opened before the rotation is left.

What you get

  • A stale finding, or one hashed from a different string, never rotates anything.
  • Proof in every rotated execution: the new password logs in, Postgres rejects the leaked one, and the sessions opened with it are gone.
  • No password in clear text: OpenBao responses are stored encrypted, and the tasks keep only hashes, usernames and timestamps.
  • One execution at a time, so a second report of the same leak waits and then finds its fingerprint stale instead of rotating again.
  • Labels outcome, role, sessions_open, sessions_ended and sessions_left on every execution.

Who it's for

  • Security and platform teams that manage Postgres application passwords with OpenBao static roles and receive secret-scanning findings.
  • Teams that need an approved, recorded response to a leaked credential, with evidence that the old one no longer works.

Why orchestrate this with Kestra

  • The scanner calls Kestra directly, and each leak becomes its own execution with logs, labels and an approval form.
  • encryptBody, secret() and hash comparisons keep the credentials out of the execution data.
  • OpenBao, Postgres and psql are called directly from one YAML file, which is also the runbook.

Prerequisites

  • OpenBao with the database secrets engine at database/ and a static role for the application user:

    bao secrets enable database
    bao write database/config/app-db plugin_name=postgresql-database-plugin \
      connection_url='postgresql://{{username}}:{{password}}@localhost:5432/app' \
      username=bao_admin password=<password> password_authentication=scram-sha-256 allowed_roles=app
    bao write database/static-roles/app db_name=app-db username=app_user rotation_period=24h
    
  • A Postgres role for Kestra: create role kestra_monitor login password '...'; grant pg_read_all_stats, pg_signal_backend to kestra_monitor;

  • kestra.encryption.secret-key in the Kestra configuration (for example openssl rand -base64 32). encryptBody needs it.

  • Docker on the Kestra host for the psql check.

  • A scanner job that sends the fingerprint, for example after gitleaks: jq -j '.[0].Secret' leaks.json | sha512sum | cut -d' ' -f1.

Secrets

  • OPENBAO_TOKEN: a token whose policy allows only read on database/static-creds/<role> and update on database/rotate-role/<role>.
  • PG_MONITOR_PASSWORD: the password of monitor_user.
  • LEAK_WEBHOOK_KEY: the key in the webhook URL.

Quick start

  1. Configure OpenBao and Postgres, add the secrets, set openbao_addr and the pg_* variables, and save the flow.
  2. Post a fingerprint of the current password to /api/v1/main/executions/webhook/company.security/openbao-leaked-postgres-credential-rotation/<LEAK_WEBHOOK_KEY>.
  3. The execution pauses and its logs list the sessions. Click Resume, choose ROTATE_AND_TERMINATE and add a note.
  4. The summary log and the labels show the rotation time and the sessions that were ended. Post the same fingerprint again: it ends with outcome: not-current.

Things to know

  • Applications must read the password from OpenBao when they connect. ROTATE leaves their sessions alone, to reconnect at the next deploy.
  • Sessions are compared with OpenBao's last_vault_rotation, so keep the OpenBao and Postgres clocks in sync.
  • While one leak waits for approval, other reports queue behind it.
  • The fingerprint is an unsalted SHA-512: fine for the random passwords OpenBao generates, not for short human-chosen ones.
  • old_login fails the execution if the leaked password still logs in, for example when pg_hba.conf trusts the client's address.

How to extend

  • Notify the approvers from onPause on approve.
  • Close the scanner alert after a successful rotation.
  • Use rotate-root when the leaked secret is the engine's own connection password.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.