tfv server
Rules and permissions
Per-project RBAC and required approvals in repos.yaml, per-command permissions, and repo-level tfv.yaml.
Rules live in repos.yaml on the server (TFV_REPOS_CONFIG, default /data/repos.yaml), or in
the repos value of the Helm chart. Because they're on the server, a pull request can't change
them.
repos.yaml
repos:
- id: github.com/acme/*
require_apply_project: true # same as the env var, per repo
apply_requirements: [mergeable]
projects:
- match: prod/**
permissions:
apply: [team:platform-admins] # read|write|maintain|admin, team:x, user:x, codeowners, anyone
apply_destroy: [admin] # plans that delete or replace
state_read: [team:platform] # state show, show, output (optional)
approvals:
- { from: team:platform-admins, count: 2 }
- { from: team:security, count: 1 }
- match: "**"
approvals: [{ from: write, count: 1 }]Who can do something is one of: a repo role (read, write, maintain, admin), team:<name>,
user:<name>, codeowners, or anyone.
Approvals
- Only approvals of the current commit count.
- The author's own approval never counts.
- Each project needs only its own approvals.
Commands that edit the state directly (outside a plan and apply) also need the project's approvals, like an apply.
Default permissions
When no rule applies:
| Permission | Covers | Default | Not set for a project? Uses |
|---|---|---|---|
plan |
plans, validate, providers, fmt, state list |
write | |
apply |
applies | write | |
apply_destroy |
applies that delete or replace | maintain | |
unlock |
releasing another PR's lock | maintain | |
state_read |
state show, show, output |
write | plan |
state_write |
import, taint, untaint |
write | apply |
state_remove |
state rm, state mv, force-unlock |
maintain | apply_destroy |
The last three cover the Terraform commands. When a project doesn't set them, they use the rule
they extend, so they're never looser: limit apply_destroy to admins and state rm is admin-only
too.
Per-command permissions
Each command also has its own key, for exceptions: state_list, state_show, show, output,
validate, providers, fmt, import, taint, untaint, state_rm, state_mv,
force_unlock. A command that isn't set uses its group; [] means nobody.
permissions:
state_remove: [admin] # state rm, state mv, force-unlock: admins
state_mv: [maintain] # except state mv: maintainers too
force_unlock: [] # and nobody may force-unlockA repo's own tfv.yaml
A repo's tfv.yaml can name projects, pin versions, and add stricter rules, but never looser
ones. It's read from the base branch, so a PR can't change its own rules.
In Helm values
The chart takes the same rules under repos:
repos:
repos:
- id: github.com/acme/infra
projects:
- match: prod/**
permissions:
apply: [team:platform-admins]
apply_destroy: [admin] # also covers state rm / state mv / force-unlock
force_unlock: [] # single commands can be set too; [] = nobody
approvals: [{ from: team:platform-admins, count: 2 }]Policy checks and the two-person rule go in the same file; see policy checks and safety.
Based on packages/server/README.md and charts/tfv-server/README.md in the tfv repo.
