Install Vizier Local

Vizier Local is free to download with an IaC Bazaar account. It runs OpenTofu or Terraform for you, and refuses to run a module whose provenance it cannot check. This page takes you from an empty directory to a proven apply, then to running your own modules.

Install

Downloading Vizier needs an IaC Bazaar account; it is free and nothing is bought. Create one, then either download the archive for your machine from your account, or create a token on Registry tokens and use the installer.

On macOS and Linux the installer resolves the latest release, downloads the right archive for your machine, and refuses to install if its digest does not match. A tool whose job is checking what you run has no business installing itself unverified.

macOS, Linux
export IACBAZAAR_TOKEN=iacb_...    # Account > Registry tokens
URL=https://raw.githubusercontent.com/CyberCoreSystems/vizier/main/install.sh

curl -fsSL "$URL" | sh                               # the latest release
curl -fsSL "$URL" | VIZIER_VERSION=1.7.2 sh          # or pin a version
curl -fsSL "$URL" | VIZIER_BIN_DIR=~/.local/bin sh

On Windows, download the zip from your account, or fetch it with the same token. The installer script stops on Windows with that instruction rather than guessing.

Windows (PowerShell)
$v = "1.7.2"
$name = "vizier_" + $v + "_windows_amd64.zip"
$headers = @{ Authorization = "Bearer " + $env:IACBAZAAR_TOKEN; Accept = "application/json" }
$d = Invoke-RestMethod "https://www.iac-bazaar.com/api/vizier/download/$name" -Headers $headers
Invoke-WebRequest $d.url -OutFile vizier.zip

# refuse the archive unless it matches the published digest
if ((Get-FileHash vizier.zip -Algorithm SHA256).Hash.ToLower() -ne $d.sha256) { throw "checksum mismatch" }

Expand-Archive vizier.zip -DestinationPath .   # put vizier.exe on your PATH

Confirm it is there:

$ vizier version
vizier 1.7.2

The engine

Vizier does not replace OpenTofu or Terraform - it runs one of them. Install OpenTofu (or Terraform) and make sure it is on your PATH. vizier info reports which one it found, which is the answer to most "it works on my machine" questions.

To pin a specific engine, pass --tofu-bin or set VIZIER_TOFU_BIN. A named engine is a requirement, not a preference: if it cannot be run, Vizier stops and says so rather than falling back to whatever is on PATH, which would not be the engine you asked for.

Your first module

Ask the catalog for a module and it prints the exact source line to paste. A catalog source always names a version: an unpinned module would change under your tree without your tree changing, which is the drift Vizier exists to catch.

find a module
$ vizier catalog list
aws-acm                    live_tested   signed   ACM Certificate (DNS-validated)
aws-s3-bucket              live_tested   signed   AWS S3 Bucket (hardened)
...
183 module(s). `vizier catalog show <slug>` prints the source line to paste.

$ vizier catalog show aws-s3-bucket
slug:     aws-s3-bucket
version:  1.1.0
status:   live_tested
signed:   true (catalog claim; `vizier verify` checks it)
sha256:   87b4ffc46b3964c6c7c004ebf75de5c5e9c0e509c82cc8af2254bb3282d3a005
source:   iacbazaar://[email protected]

Put that source in a vizier.hcl, in its own directory. That directory is a unit: one module, one state, one set of inputs.

vizier.hcl
terraform {
  source = "iacbazaar://[email protected]"
}

inputs = {
  bucket_name = "acme-artifacts-eu-north-1"
}

Now check it before running anything. verify touches no cloud and needs no credentials: it asks the catalog what was published, checks the signature against a key compiled into the binary, and reports what it found.

$ vizier verify
[ok] . - [email protected] proven (live_tested, signature verified)

signature verified means the signature was checked, not that the catalog claims one exists. live_tested means that module was really applied against a live cloud account, verified, and destroyed again before it was published - what that does and does not claim.

vizier scaffold iacbazaar://aws-s3-bucketwrites the same file for you and fills in the current version. A module's input list is part of its published contract, so run vizier login first if you want the inputs filled in too.

Plan, apply, destroy

These are the commands you already know. Vizier verifies first, materialises the module, writes the backend if the unit declares one, and then runs the engine.

vizier plan            # inside the unit directory
vizier apply
vizier destroy

vizier run-all plan    # every unit in the tree, in dependency order
vizier verify          # proof status only, no engine, no cloud

Apply and destroy prompt for confirmation. Where there is no terminal, they refuse rather than assume: CI has to pass --auto-approve and say so out loud, because silence is not consent.

Your own modules

Most teams have modules of their own. Vizier runs them, but it will not pretend to have checked something it has not: a module we did not publish has no signature from us. There are three ways forward, in descending order of evidence, and with none of them Vizier stops.

$ vizier plan
[BLOCK] . - git::https://github.com/acme/infra.git//vpc is not an
        IaC Bazaar module, so there is nothing to verify it against.
        Pin it with verify { source_sha256 = "..." }, allow-list its
        prefix with allow_unverified, or set allow_any_source = true
        to run unpinned code deliberately

1. Pin the digest. You declare what the code should be, and Vizier checks what it fetched against that. This is real provenance, supplied by you rather than by us, and it needs no catalog and no signing key. Run it once unpinned and Vizier prints the digest to paste.

vizier.hcl
terraform {
  source = "git::https://github.com/acme/infra.git//vpc?ref=v2.4.0"
}

verify {
  source_sha256 = "9f2c...the digest vizier printed..."
}

If the tree ever differs from that digest, the run stops and shows both values. A tag can be moved; a digest cannot.

2. Allow-list a prefix. allow_unverified = ["git::https://github.com/acme/"] covers a whole repository or organisation. Admitted, and recorded in the receipt as unverified.

3. Say so for the whole tree. allow_any_source = true means this tree runs code from anywhere. It is explicit, and the receipt says so.

Public registry modules

Modules from the public Terraform registry work, in both the plain and the tfr:// spellings. Pin the version in the source: a registry module with no version means whatever was published this morning.

terraform { source = "terraform-aws-modules/vpc/aws?version=5.1.0" }
terraform { source = "tfr:///terraform-aws-modules/vpc/aws?version=5.1.0" }

# git, an archive over HTTPS, S3, GCS and a local path all work too
terraform { source = "../../modules/vpc" }
A query parameter a registry module does not understand - ?ref=main, say - is refused rather than ignored. An ignored pin is worse than a rejected one, because the run looks pinned while running code nobody chose.

Where state lives

A fetched module is a cache, unpacked into .vizier-module beside the unit, and it can be thrown away and fetched again. Your state is not a cache. With a local backend the engine writes terraform.tfstate next to the configuration, so it sits inside that same directory - and --source-update is careful to move it aside and put it back rather than delete it with the rest.

vizier plan --source-update    # re-fetch the module, keep the state beside it
No changes. Your infrastructure matches the configuration.

For anything shared, declare a remote_state block and let Vizier write the backend file. vizier backend creates and moves the state stores a tree writes to.

In CI

There is a GitHub Action, and worked examples for Jenkins, Azure Pipelines, AWS CodeBuild, Atlassian and Spacelift in the public repository. Pin a version in CI rather than taking the latest. Every pipeline downloads Vizier with an account token: store one as a secret named IACBAZAAR_TOKEN.

.github/workflows/infra.yml
- uses: CyberCoreSystems/[email protected]
  with:
    token: ${{ secrets.IACBAZAAR_TOKEN }}
    action: plan
    dir: envs/prod
    verify-mode: enforce

Leave verify-mode on enforce. warn still runs modules that failed the check and records the bypass in the receipt, which is a different thing from a pipeline that stops.

For a team

Everything above is one operator on one machine, answerable to the policy written in the tree. When the policy needs to belong to the organisation instead - roles, an evidence floor per environment, review before an apply, shared state locking and durable history - that is Vizier Central, which you host yourself.

You can see it before you decide anything about it. Point it at a throwaway Postgres, run vizier central demo, and the console comes up with a worked estate in it rather than an empty grid: three projects, five environments, three cloud accounts, two of them deliberately left unbound because that is the state the estate map exists to make visible. It refuses an organisation that already has projects, so it cannot touch anything real, and vizier central demo --remove deletes exactly what it created.