AegisDB
中文GitHub
Database access gateway

Every statement
passes the gate

Six ways in, one decision chain. Every statement is judged on its own — allow, block, or send for approval — and every one of them lands in an audit chain that cannot be edited afterwards.

One binary serves both the API and the console · PostgreSQL is its only store

Why a gate

Database permissions stop at "can you connect"

They cannot answer the question that actually matters: should this statement run, here, now?

01

The grain of authorization is wrong

An account can express "this person may connect to this instance", not "they may SELECT, but a DROP goes to approval".

02

Approval lives in the process, not in the path

The ticket gets approved, and the engineer still picks up credentials and runs it themselves. Which statement was approved and which one ran — the system knows neither.

03

Auditing is after the fact, and editable

Logs scatter across general logs on each host, and whoever can reach the database can usually reach the log.

Decision chain

A statement arrives. 4 gates stand in the way.

All 4 layers are stored per tier, and a tier is not an environment: prod-hk and prod-sh are governed by the tier they both hang off, so adding one more production instance copies no rule rows at all.

  1. Menu permissionPassl2 × terminal
  2. Capability matrixPassddl @ prod = approve
  3. High-risk command dictionaryHitDROP @ prod = high
  4. Missing-WHERE blockPassstrictNoWhere @ prod = on
VerdictSend for approval
dictDenyPROD may not run directly — sent for approval

This demo runs entirely offline in your browser. The logic is ported from the gateway's decision engine, seeded with the built-in default rule set. Your own deployment can change the dictionary, the capability matrix, or tier properties — the verdicts follow. Multiple statements are split on semicolons and judged one by one: quotes, comments, MySQL executable comments and custom delimiters are all recognised. Whole stored-procedure bodies and similar script forms are out of scope here — judge those with the product itself.

Core capabilities

Six things it watches for you

The mechanism and the boundary of each are set out on the how-it-works and security pages.

allow / block / approve

Real-time, statement-level decisions

The decision sits in the function all six entry points call, not on the entry points. A pasted batch is split on semicolons and judged one statement at a time; the batch takes the strictest verdict.

ADR 0010

Approved ≠ executed for you

Terminal tickets: approval only authorises, someone still has to come back and press execute, and every gate is recomputed against whoever actually pressed the button. Releases: execution belongs to the pipeline stage. Execution-window and export tickets: no runnable command at all.

ADR 0015

Execution windows close themselves

A window is itself approved, is scoped to one database, and stops covering the present moment when its time is up. It only downgrades "approve" to "allow"; a deny is never relaxed.

SHA-256

Tamper-evident audit chain

Each record hashes as SHA256(previous hash + payload), and prev_hash carries a single-column unique index — a forked chain is refused by the database rather than by application discipline.

ADR 0009

Masking happens before data leaves the gateway

Only two places in the gateway read result rows out of a user’s SQL: terminal results and data exports. Masking hangs on both.

MySQL / TiDB / DWS / Oracle

Standards review before release

87 built-in rules: 62 are lifted from four internal database standards and cite the clause they came from, and 25 are the platform’s own. It is not a gate: it takes no part in the execution decision.

Console replicas

What the console actually looks like — not our word for it

A UI-level replica rendered from the real rule data, not a screenshot. The approval ticket below has been approved, and the button still says "Execute".

Approval ticket
AP-20260919-0042Approved
Initiator
linwei@vela.io
Target instance / database
PRODprod-mysql-01 · orders

SQL

ALTER TABLE orders ADD COLUMN note varchar(64)

Rule hit

dictDenyPROD may not run directly — sent for approval

Approval chain

  • zhaoyun@vela.io
  • wangfang@vela.io

The gateway re-checks the rules before executing — this ticket may have sat in the queue for hours.

Illustrative button, not clickable — approved ≠ executed on your behalf (see the "how it works" page, layer two).

Console UI replica · not a screenshot

Target databases

Real connections, judged per dialect

The engine dropdown for a new instance is exactly these 7, and the families are drawn by which wire protocol an engine speaks, not by vendor. What gets judged is always what you typed — meta-commands are translated only after the verdict is in.

PolarDB in that list means the MySQL-compatible edition; PolarDB for PostgreSQL speaks the PostgreSQL protocol and belongs to the other family.

MySQL family

  • MySQL
  • PolarDB
  • TiDB
  • MariaDB

PostgreSQL family

  • PostgreSQL
  • GaussDB (DWS)

Oracle

  • Oracle
Quick start

Create one database, then start two processes

A local PostgreSQL has to exist first; the server applies its own migrations on startup.

Backend · listens on :8080

# First: createdb vela_gateway
cd backend && go run ./cmd/server

Frontend · http://localhost:5173

# Vite proxies /api to :8080
cd frontend && npm install && npm run dev

Full deployment guide →

Put the gate on the path

If the migrations do not finish on startup, it exits — a gateway missing half its tables still turns the health check green while every request comes back 500.