Stacks: OpenTofu with approvals
A stack is an OpenTofu (or Ansible) configuration that Velrix runs for you. Its state is kept in Velrix, sealed, with every version. Each run plans in a sandbox first; you look at what it would change, and only then does it apply, exactly the plan you saw. With four eyes, someone other than the person who started the run must approve it.
This guide sets up an OpenTofu stack for an organisation. Personal stacks work the same way, without the approval step.
What you get
- No state on laptops. The state lives in Velrix, encrypted, with its history. A run locks it, so two applies never race.
- No long-lived keys. Each run gets a short-lived key that acts as the person who started it, with only the scopes the stack allows. It is dropped the moment the run ends.
- Four eyes and an audit trail. Who started a run, who approved it, and what it changed, are kept on the stack.
- Secrets stay secret. Secret variables are sealed, handed to runs only as secrets, and masked in every log line.
- Works offline. Runs take providers from your installation’s own mirror, never from the internet.
1. Create the stack
Open Stacks and choose New stack.
- Name: for example
network. - Kind: OpenTofu.
- Source: the Repository as an https git URL, with a Branch, tag or commit and the Directory the configuration lives in. For a private repository, add a Deploy token; it is sealed and never shown again. You can also upload a
.tar.gzof the source instead. - Approval: Another person.
- What runs may call: the API scopes a run needs, words apart, such as
machines ssh-keys. A run can never do more than the person who started it may.
Choose Create stack.
2. Add variables
On the stack’s Settings tab, under Variables, add what the configuration needs. Runs get each one as var.<name>.
Tick Secret for passwords and tokens. A secret is sealed in Velrix, handed to runs only as a secret, never shown again, and masked in the output: a line that would print it shows •••••• instead.
3. Plan
On the Runs tab, choose Plan. Velrix starts a sandboxed run that fetches the source, runs tofu plan, and keeps the plan file sealed.
The run’s page shows what the plan changes, as counts and resource by resource: what it creates, updates, replaces and destroys. Destroys and replacements stand out. The output’s last lines are there too, masked.
If nothing differs, the run ends as No changes.
4. Approve and apply
The run now says Waiting for approval, with who started it.
- You cannot approve your own run. Ask a colleague who holds Approve plans in the organisation. Organisation admins and owners do.
- The approver opens the run, reviews the plan and the source it came from, and chooses Approve and apply.
Velrix then applies exactly the plan that was approved, in a new sandbox, still acting as the person who started it. Approving lends no rights of its own. If the state moved on since the plan, OpenTofu refuses it and the run ends as Stale plan: plan again.
To throw a plan away, choose Discard. To stop a running one, Cancel run.
5. Watch for drift
Set Drift check every (hours) on the Settings tab. Velrix then plans on that schedule, never applies, and posts a notice when something changed outside the stack. The run ends as Drifted, and the notice opens it.
Use the state from a laptop or CI
A stack’s state also works on its own, for OpenTofu runs you start elsewhere. The State tab shows the snippet to paste into your configuration:
terraform {
backend "http" {
address = "https://velrix.example.com/stacks/<stack>/state"
lock_address = "https://velrix.example.com/stacks/<stack>/lock"
unlock_address = "https://velrix.example.com/stacks/<stack>/unlock"
lock_method = "POST"
unlock_method = "POST"
username = "velrix"
}
}
The password is an API key with the stacks:state scope (the API reference is in your realm’s Docs window):
export TF_HTTP_PASSWORD=vlxk_…
tofu init
tofu apply
The State tab lists every kept version. You can Restore an older one (it becomes the current state, with the next serial) or Download it. A state holds secrets in the clear, so every download is recorded with your name. Force unlock opens a lock whose holder is gone, also recorded.
Providers in an installation without internet
Runs fetch nothing from the internet. The Velrix provider is always there. Any other provider must be in your installation’s mirror first:
- Under Mirror on the Stacks list, import the provider by name and version, such as
hashicorp/random 3.6.3. - Velrix downloads it once, checks its signed checksums, and keeps it in your registry. This one step needs a way out to the provider’s own registry.
A run that needs a provider not in the mirror fails and names it: not in the realm’s mirror: hashicorp/random.
Ansible
An Ansible stack works the same way. The plan is ansible-playbook --check --diff, the summary is each host’s changed, ok, failed and unreachable counts, and the apply is the real run of the same commit.
- Each Ansible stack has its own SSH key pair. Its Settings tab shows the public half, with Add to SSH keys, so your machines can let it in.
- Join the project network lets runs reach the private addresses of your machines on the server the run lands on. Without it, runs reach only public addresses.
- With no inventory file, the inventory is your machines.
- SSH host keys are checked on every run. Velrix machines’ keys are known before they boot; other hosts’ keys are pinned on first use, and a run against a changed key stops before it connects.
Next
- The OpenTofu and Terraform provider and the Ansible collection, in your realm’s Docs window