temporalio / temporalio/temporal

Support runtime refresh of the DB username (not just password) for rotating dynamic credentials

Open
#12,193 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Go
Stars
23.2k
Forks
1.9k
Avg merge
2d 8h
Merged PRs (30d)
228

Description

Is your feature request related to a problem?

Temporal can refresh the DB password at runtime (cfg.PasswordCommand → a refreshable DSN),
but the username is fixed in static config. Credential systems that rotate both fields
per lease — HashiCorp Vault's database secrets engine (per-lease users like entity:serv-xxxx) —
therefore cannot be used without a pod restart on every rotation. This is the sibling of #9156:
both need credentials re-resolved at runtime, but #9156 rotates a token (password-like) while
this rotates the username too.

What already exists (main)
  • common/persistence/sql/sqlplugin/db_handle.goDatabaseHandle.connect func() (*sqlx.DB, error)
    is re-invoked on every reconnect(force); ConvertError triggers reconnect(true) on
    needsRefresh(err) and on connection errors (ErrBadConn, EOF,
    ECONNRESET/ECONNABORTED/ECONNREFUSED). Combined with MaxConnLifetime, connections are
    periodically rebuilt and the connect callback re-runs.
  • common/persistence/sql/sqlplugin/postgresql/session/session.gocreateConnection already
    supports a refreshable DSN via cfg.PasswordCommandCreateRefreshableConnection(buildDSN).
The gap

buildDSN reads cfg.User as a static value, so even the refreshable path only refreshes the
password. There is no equivalent of PasswordCommand for the username.

Proposed solution

Extend the refreshable-credentials mechanism so the username is re-read on each connect()
e.g. a UserCommand (analogous to PasswordCommand) or a credentials-provider that yields both
username and password at DSN-build time. On reconnect (driven by MaxConnLifetime or
ConvertError), the pool then re-authenticates with the rotated username+password without a
restart. This reuses the existing DatabaseHandle.reconnect() + PasswordCommand infrastructure,
generalizing the password refresh already present.

Environment

Version: v1.31.2 (mechanism unchanged on main). Plugin: postgres12 / postgres12_pgx.
Credentials: Vault per-lease username+password delivered as a K8s Secret by the Vault Secrets
Operator.

Related
  • Cloud Database Cert/IAM Connections #9156 (cloud/IAM DB auth — same runtime
    credential-resolution need; notes DatabaseHandle.reconnect() already re-runs the connect
    callback).
  • DSN username-encoding bug (buildDSN interpolates cfg.User raw, breaking usernames with :)
    — tracked separately.
  • Chart-side prerequisite (sourcing the username from a Secret): temporalio/helm-charts#985.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with common/persistence/sql/sqlplugin/db_handle.go to trace DatabaseHandle.connect and reconnect(force), then read common/persistence/sql/sqlplugin/postgresql/session/session.go and its createConnection/buildDSN flow. Check how PasswordCommand and CreateRefreshableConnection are used. Done means the refreshable connection path re-reads both username and password on reconnect, including reconnects driven by MaxConnLifetime or ConvertError.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql
Domain
backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.