Skip to content

AUTH_USER never applies: the per-database auth_user added in #56 always overrides it #134

Description

@jclaveau

AUTH_USER sets auth_user in the [pgbouncer] section, which pgbouncer treats as the default for databases that do not name one of their own. But generate_config_db_entry always writes a per-database auth_user:

port=${DB_PORT:-5432} auth_user=${DB_USER:-postgres}

and the per-database value wins. So AUTH_USER never applies to a generated entry.

Reproducing

Per-entry auth_user pointing at a role that does not exist, global AUTH_USER pointing at one that does and whose password is in userlist.txt:

$ docker run -d --network app \
    -e DB_HOST=pg -e DB_NAME=appdb \
    -e DB_USER=ghostuser -e DB_PASSWORD=ghostpw \
    -e AUTH_USER=postgres \
    edoburu/pgbouncer
[databases]
appdb = host=pg port=5432 auth_user=ghostuser
[pgbouncer]
auth_user = postgres

Connecting as a user absent from userlist.txt, so that the auth_query path runs:

$ psql "postgres://other@pooler:5432/appdb"
psql: error: FATAL:  password authentication failed for user "ghostuser"

The lookup was attempted as ghostuser, never as the configured AUTH_USER.

The second symptom

The same line explains a confusing error in the default configuration. Started with neither DB_USER nor AUTH_USER, an entry still advertises auth_user=postgres, so an unknown user gets:

C-0x…: appdb/(nouser)@… closing because: password authentication failed for user "postgres"
S-0x…: appdb/postgres@… closing because: password authentication failed for user "postgres"

naming a role the operator never configured. The real situation is that the connecting user is absent from userlist.txt and no usable auth_user exists. Without an auth_user on the entry, pgbouncer would have said so plainly.

How the two came to collide

AUTH_USER arrived in 99b51ec (2019) and is the README's documented route to auth_query. The per-database auth_user arrived much later, in 6591cb9 (2023, #56), as a one-word change:

-port=${DB_PORT:-5432} user=${DB_USER:-postgres}
+port=${DB_PORT:-5432} auth_user=${DB_USER:-postgres}

That fixed a real problem — the forced user= collapsed every client into a single identity on the server — and putting DB_USER into auth_user was the point of it. AUTH_USER is not mentioned anywhere in #56, so the shadowing looks like something nobody had reason to notice: for the four years before, the two variables wrote different settings and could not conflict.

Suggested fix

Reconcile the two rather than undo either:

auth_user =  DB_USER      when set
             AUTH_USER    otherwise, when set
             omitted      otherwise
  • use auth_user instead of user option in the default db config #56 keeps working: DB_USER still drives auth_user, and clients still reach the server under their own identity
  • AUTH_USER becomes usable for the first time since it was added
  • with neither set, the entry stops advertising a postgres credential nobody configured, and an unknown user gets pgbouncer's own clear message instead of a failure naming postgres

One case to weigh before changing the last line: a mounted AUTH_FILE may hold a postgres credential with no DB_* and no AUTH_USER set, and that setup would lose auth_query if the entry stops defaulting. Keeping the postgres fallback while still honouring AUTH_USER would cover it, at the cost of the confusing error staying.

Related

Reproduced on edoburu/pgbouncer:latest.

Assisted-by: Claude:claude-opus-5[1m]

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions