Before You Start
Work through Requirements first. The installer validates most of it and refuses to run rather than failing halfway, but a missing certificate or an unopened firewall rule still costs you the slot. Everything below runs from your control machine — your laptop, a jump host, or a CI runner. It is not the target.The Value Gate
Before Ansible is invoked at all, the installer refuses to run a deploy while any of the following is true:There is no flag to skip the gate. It exists because each of these produces a failure that is either silent or destroys its own evidence.
Setup
1
Verify the release, before you unpack it
ROOTKey delivers a release as a single archive, and four files reach you by two different
routes. The archive comes through the delivery channel; It prints the archive’s own SHA-256 for you to compare against the value we sent you
separately, checks the signature against The bundle carries the Helm charts, the Ansible roles, the installer, and — for an air-gapped install — every container image plus the k3s and Helm binaries.
SHA256SUMS, SHA256SUMS.sig and
cosign.pub come from Trust and Verification. That separation is
the point: a checksum that travelled with the file it checksums proves only that the two
arrived together.Put the archive and those three files in one directory, with the verifier, and run it:cosign.pub, and checks every file from inside
the archive without unpacking it. It ends with Verified. Safe to unpack. or it tells you
what failed and says not to install.Only then unpack:install.sh does not verify anything for you. This is a deliberate step, and nothing later
in the install will fail if you skip it.2
Run the preflight, before touching anything
The preflight is read-only. It changes nothing on the target and is deliberately not blocked by the value gate, so you can run it before anything is filled in.It reports PASS, WARN or FAIL for CPU, RAM, disk, operating system, and the required ports. Resolve every FAIL before continuing. A host with fewer than eight vCPUs fails this check.
3
Fill in the inventory
Copy the example and edit your copy. The real file is git-ignored, so it never travels back into the repository.For Scenario C, one host with SSH details. For Scenario B,
ansible_connection=local and the kubeconfig passed on the command line.Then set the platform hostname in the same file, under [rootkey:vars]:4
Fill in the vault
Copy the example vault and fill in every value. See Configuration Reference for what each key is and where it comes from.Store the vault password in a file the installer can read, and keep that file out of version control:
5
Create your values file
Copy the example and edit your copy:Three things must be set:
- Every image
repositoryandtag— the registry ROOTKey gave you and the released commit SHA of each service. The gate rejects the shipped placeholders. - The platform hostname, on the
platform-frontendIngress. PUBLIC_FILE_BASE_URL, underglobal.envOverrides:
Do not append the bucket name to that URL. The MinIO Ingress prepends it from the vault, so the bucket name lives in exactly one place. Two copies drift, and the failure when they do is a 404 on every file.
6
Load the TLS certificate into the cluster
The installer consumes a Secret; it does not create one. Load your certificate for the platform hostname:The Secret name must match A Secret in the wrong namespace is invisible to the Ingress, and the failure looks like a certificate problem rather than a placement one.
ingress.tls[].secretName in your values file and rootkey_tls_secret_name in the inventory. rootkey-tls is the default both expect.The ordering, precisely. The namespace is created by the secrets stage (stage 3), and the certificate is not consumed until the Ingress is created in the deploy stage (stage 7). So you have two correct options:7
Run the installation
- Scenario C
- Scenario B
--airgap true to load images from the bundle instead of pulling them.--values flag is not optional in practice: without it the installer falls back to the shipped example, which is full of placeholders, and the gate refuses.The run executes twelve stages in order — preflight, Kubernetes runtime, secrets, database, chart staging, in-cluster stateful services, the Data Plane itself, the plan seed, the contract seed, host hardening, the post-install checklist, and the healthcheck that writes the signed install manifest.8
Watch for the lines that matter
Three messages tell you whether the parts that fail silently actually worked.
contract-seed — on a fresh install you want contratos semeados. On a re-install you want skip: já há contratos, which means the guard held. If you see skip: o fixture não veio no bundle, the platform will install cleanly and return 500 on the first file upload, with no cause in the gateway log.The bucket job — bucket ready: <name> (anonymous download enabled). If it says anonymous read NOT granted, stored files will return AccessDenied to every browser.The MinIO precondition — it runs before any Helm command in the stateful stage. If it fails, it names which of the three values is missing and nothing has been installed yet.What Runs, In Order
Stages 11 and 12 are not optional extras, and stage 11 is the one to read. Everything
before it reports whether a step succeeded. The checklist asks a different question, and it
is the question you care about: every workload can be
Running, Helm can report success, and
the deployment can still be unusable.A clean run ends with Nothing checked here is missing, followed by a count of items that
need confirming by hand — things no check inside the cluster can see for you. Read those.Re-run the checklist on its own at any time with --tags verify. It changes nothing.The hardening stage, and the net underneath it
Stage 10 reconfigures the firewall of the host you are connected to. That is the one stage that can, in principle, end your own SSH session — and on a remote host with no console, a firewall change that goes wrong is the difference between a failed install and a machine nobody can reach. It is not left to chance. Before the firewall is touched, the installer writes a small script to the target and arms a systemd timer against it. If the hardening pass completes and your connection survives, the timer is disarmed and you never know it was there. If it does not, the timer fires after 15 minutes and puts your access back. What it inserts is one rule, for one address — the address you are connected from, on the port you are connected on:It re-admits you, not everyone. An earlier version disabled the firewall instead, which
would have left the host open to the whole network as its idea of a safety net. If the
switch fires it also writes
/var/log/rootkey/FIREWALL-DEADMAN-FIRED, so a host that let
you back in says so rather than looking like nothing happened.Re-running the Installation
Every stage is idempotent, and an upgrade is the same command as an install.- Helm uses
upgrade --install. On a release that is alreadydeployed,--atomicis on, so a failure rolls back rather than leaving the platform half-changed. On a first install it is deliberately off: a rollback there would delete the pods, logs and events that explain what went wrong. - PostgreSQL is rotation-safe. It reads the passwords from your vault and applies them; it never generates its own, so a re-run cannot orphan your credentials.
- The seeds check before they write. The contract seed skips with a message when contracts already exist rather than duplicating them.
→ Next: Configuration Reference · Verification

