Skip to content

Access & audit

The data editor hands out direct database access, so it’s deliberately fenced with RBAC, auditing and a server-side-only connection model.

Access is enforced per resource by Pier’s role-based access control:

ActionMinimum role
Browse databases / schemas / tables / collections / keysViewer
View structure, rows, documents, key valuesViewer
SQL Runner (any statement)Editor
Mongo Shell (any script)Editor
Redis command (any command)Editor

The split is intentional: a teammate can be given read-only insight into production data without the ability to mutate it. Anything that could write — every runner, regardless of whether the specific statement happens to be a SELECT — requires Editor.

Every runner execution is recorded in the db_query_log table, whether it succeeds or fails. Each row captures:

  • Who — user id and username.
  • Where — the service and the target database.
  • What — the SQL / command / script text, and its kind (read, write, redis, mongo).
  • Outcome — status (ok / error), row count, duration, and the error message on failure.

Logging is best-effort and never blocks a query — an audit-write failure won’t mask a successful (or failed) statement. Browsing reads aren’t logged; the audit trail focuses on the runners, which are the actions that can change data.

Connection credentials come from the service’s encrypted environment (env_json, AES-256-GCM at rest) and are decrypted in memory only at request time. They are:

  • never displayed in the UI,
  • never written to logs,
  • read from the standard image variables — POSTGRES_USER / POSTGRES_PASSWORD, MYSQL_ROOT_PASSWORD (or MARIADB_ROOT_PASSWORD), MONGO_INITDB_ROOT_USERNAME / MONGO_INITDB_ROOT_PASSWORD, REDIS_PASSWORD.

Pier core runs on the host and reaches each database over the pier-net Docker network — the container’s internal IP and port — falling back to 127.0.0.1:{host_port} only when a port is published. This means:

  • A private database never has to be exposed to the internet for you to inspect it.
  • The traffic stays on the internal Docker bridge between the host process and the container.

For the SQL browser, identifiers (schema/table/column names) arrive as parameters but are never trusted blindly:

  • the (schema, table) pair is confirmed to exist via information_schema before any string-built SQL touches it,
  • every identifier and literal is engine-quoted,
  • column names always come from the catalog, never from the client.

The SQL Runner itself executes the operator’s statement as-is — that’s the point of a runner — which is exactly why it’s gated behind Editor and fully audited.

  • Overview — supported engines and where to find the Data tab.
  • SQL Runner — limits and behavior of the SQL runner.