Vizier Central
The same binary that runs one operator on one tree also runs a control plane for a whole team. Central adds the three things a local console structurally cannot have: roles that hold, one evidence floor per environment, and history that outlives the process. You host it, in your network, against your Postgres.
What it does not hold
No cloud credentials. Not encrypted, not envelope-encrypted, not “just the secret”. A cloud account here is a pointer to an identity you already control - a role ARN, a subscription and client id, a service account to impersonate - and the runner federates for short-lived credentials at run time. It holds no Terraform state either: state stays in your backend. A full compromise of this database teaches an attacker which role ARNs you use, and that is the whole blast radius.
Which way the arrows point
Central does not dispatch work. A local vizier - a laptop, a CI job, a self-hosted runner - announces a run it is about to perform, is told whether it may and what evidence this organisation demands, performs the run with its own credentials, and reports the outcome with the receipt. Report-in, not dispatch-out.
Start -> "about to apply env X at commit Y, citing change Z"
Central answers with the floor to enforce, or refuses.
<run> on your machine, your credentials. Central is not involved.
Finish -> outcome + receipt, kept verbatim.That direction is not a limitation to be lifted later. A control plane that dispatched would need a credential for every account it deploys into, which is the one thing this design refuses to become.
1. Run it
Postgres 14 or newer. The schema is applied on start, so an empty database is enough. It speaks plain HTTP and expects your own TLS termination in front of it - an ingress, a reverse proxy, a tunnel - and binds loopback by default so that putting it on a network is a decision somebody makes rather than one they inherit.
export VIZIER_DATABASE_URL='postgres://vizier:...@localhost:5432/vizier'
vizier central init --org "Your Company" --owner [email protected]
# prints one token, ONCE. Only its hash is stored.
vizier central serve --listen 127.0.0.1:84802. Add people
Run on the host: this command talks to the database directly, which is how the first tokens for a new deployment get made. Afterwards an owner can add members from the console.
vizier central token --email [email protected] --role operator
vizier central token --email [email protected] --role admin| Role | May |
|---|---|
| viewer | Read the estate, the runs and the receipts. Nothing else. |
| operator | Plan and apply. Raise changes for review. Cannot destroy. |
| admin | Destroy, configure projects, environments, accounts and trusted keys, review changes, read the audit log. |
| owner | Manage people, rename the organisation, and weaken an environment’s floor. |
The console has a Permissions screen that reads the server's own policy table rather than repeating it, so it cannot describe a system that no longer exists.
3. Set the floor
An environment declares how much evidence it demands: a status floor, whether a signature is mandatory, whether sources must be pinned, and whether a failed check refuses the run or merely reports it. Production demanding more than a sandbox is the reason environments are rows at all.
The floor is handed to the runner at the start of every run, so nobody has to remember the right flags - and nobody can quietly not pass them. A run that asks for a weaker verify-mode than its environment demands is refused before it starts.
vizier: below this environment's floor
prod demands verify-mode=enforce and this run asked for off.
An owner can lower the floor; a runner cannot.4. Require review
Branch protection, for infrastructure. Each environment carries a count of how many people other than the author must approve a change before it may be applied there. Zero is no review, one is four eyes, two is what a regulated team usually wants on production. It defaults to zero: a control that arrives by surprise gets switched off in a hurry by whoever is mid-incident, so turning it on is a deliberate act - and turning it back down is treated as weakening the floor, which needs an owner.
A change is a pull request whose diff is the plan. A code diff tells you what the HCL says; it does not tell you that this apply replaces a database.
# the engineer proposes, pinned to an exact commit
vizier central propose \
--title "Add a read replica to the claims database" \
--head 8f2c41a9db7e5630c8a417fd2e9b05c3417ae62d \
--verb apply
# somebody else reviews. It must be somebody else.
vizier central changes
vizier central review 58384dc6 --approve --note "Replica only, no data resources."
# and the apply is now allowed, at that commit and no other
vizier apply --dir envs/prod --change 58384dc6Change ids resolve from a unique prefix, so the short id vizier central changesprints is what you paste. The commit defaults to this repository's HEAD; pass --ref to pin one deliberately.
What a governed run does
Once a tree is bound, plan, apply, destroy and run-all report into the control plane on their own. Nothing new to remember, and nothing to forget.
$ vizier apply --dir envs/prod
control plane: https://vizier.your-company.internal - prod - run c0c57866
floor: envs/prod: min_status -> live_tested
floor: envs/prod: require_signed -> trueThe floor is applied, not merely received, and it raises only: a unit that already demands more than the company minimum keeps its own setting. What it raised is printed, so nobody has to wonder why the run demanded more than their vizier.hcl says. Refusals happen before a single resource is planned, so they cost nothing:
vizier: this environment requires review: prod needs 1 approval(s) before an apply.
vizier: below this environment's floor: prod demands verify-mode=enforce, this run asked for off.
vizier: that is not the commit that was approved: approved 8f2c41a..., this run carries deadbeef...The outcome is reported either way, and especially on failure: a history containing only successes cannot answer the question people actually bring to it. The receipt stored centrally is byte-for-byte the one --receipt would have written, so the shared record cannot disagree with the file on somebody's disk.
The two rules that make review mean something
Both are enforced in the database, in the same statement that writes the row, rather than in a handler or a client. A rule enforced in a client is a rule anybody can edit out.
- The author cannot approve their own change. Not a role check - an admin who raised a change still cannot pass it. Without this, four-eyes is true on the org chart and false in the room.
- An approval is pinned to one commit. A review records the commit it was given, and an apply must carry the commit that was approved. Approve one, apply another, and the approval was theatre. This is also why a change is immutable once raised: a new commit is a new change, not an edit to this one.
Three more follow from those: an approval is spent once, so a retried pipeline cannot apply twice on one decision; a review given on an earlier commit is shown but never counted; and a run that reports itself as passed while also reporting refusals is rejected rather than stored.
5. Certify it, if a client wants proof
Review is your team agreeing. Certification is a service you do not run executing the commit in a real sandbox and returning a receipt anybody can check. When a client wants to verify your pipeline rather than take your word, that is the artifact.
$ vizier certify change 58384dc6
certifying Add a read replica at c4d8e1f0a72b
run r-8812 (--attach r-8812 to resume watching)
running
succeeded
recorded check "certify" = passed on Add a read replicaIt reads the change from Central, submits the commit that change pins - never whatever is checked out locally - waits, and records the verdict as a check. A red verdict blocks production, and nothing new enforces that: a change carrying a check that is not green was already unmergeable.
The command holds two credentials, because these are two services: your Central token annotates the change, the attestation token pays for the sandbox run. It refuses locally, before anything is billed, if the change is already closed, names no source, or pins something that is not a full commit id. A run that applied and did not tear down is recorded as failed, not passed: a leak is an incident, not a result.
A tree that does both names both, because Central reviews and the attestation service executes:
{
"schemaVersion": 1,
"kind": "central",
"endpoint": "https://vizier.your-company.internal",
"attest": "https://iac-bazaar.com",
"environment": "<environment id, from the console>",
"onUnreachable": "fail"
}6. Point a tree at it
A tree names its control plane in vizier.control.json at the root. The file is meant to be committed - that is how a team shares where the control plane is - and it refuses to hold a token, because a credential in a committed file is a credential in your git history. Your identity is stored separately, per machine.
{
"schemaVersion": 1,
"kind": "central",
"endpoint": "https://vizier.your-company.internal",
"environment": "<environment id, from the console>",
"onUnreachable": "fail"
}vizier login --endpoint https://vizier.your-company.internal
vizier central statusonUnreachable defaults to fail, and that is the safe direction: an attestation that did not happen is not an attestation that passed. Set it to warn only as a deliberate choice, and it is recorded in the receipt rather than inferred from a gap.
The consoles
Central serves its own console at the same address: an estate map you can drag to bind accounts to environments, the floor ladder ordered by strength rather than by name, the review queue, run history with every receipt kept verbatim, members, permissions, the audit log, and a live team activity feed.
The local console (vizier ui) gains a Control plane screen showing what this tree is bound to, who this machine acts as, the floor it will be held to, and what is waiting for review. Approving happens in the control plane console rather than there: the local console is one operator on one tree, and a review is a decision about somebody else's work.
Operating it
- Back up Postgres. It holds your estate, your people and every receipt. It holds nothing that would let an attacker into a cloud account.
- Terminate TLS in front of it. It speaks plain HTTP and says so loudly if you bind it to anything but loopback.
- One deployment serves one company.
initrefuses to run twice. - The live feed is in memory. Restart and every console reconnects and resumes from live, having missed what happened in between. The durable record is the run list and the audit log. Do not run two replicas behind a load balancer and expect each to see the whole organisation.
Vizier is Apache-2.0 and its source is at github.com/CyberCoreSystems/vizier. Central is part of the same binary - there is nothing extra to buy to run it.