Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rules for every module

tofu/ covers provider-API resources Flux and Kustomize cannot own, because they live outside the cluster: a DNS record, a registrar account, a tailnet policy.

It is not used for anything Flux can reconcile. Pocket ID itself is a Flux-managed workload under infra/auth/, not a tofu resource — the oidc module only registers its OIDC clients, an operation against Pocket ID’s own API that no Kustomization can express.

Rules

Read-only against OpenBao. Never let a module write to OpenBao. Anything a module mints becomes a sensitive output, pasted into OpenBao by hand.

Exception: oidc. It mints OIDC client secrets in Pocket ID, and the whole point of the module is removing that hand-paste step for this one round trip, so it writes those secrets straight to OpenBao via the vault provider. It is scoped to the oidc-writer policy — write-only on secret/data/* in one namespace, created by ansible/roles/openbao/tasks/namespaces.yml — never the root token. Every other module stays read-only.

Provider tokens are never committed. A module’s secrets.env holds only Proton Pass pass:// pointers, which are safe to commit, resolved at runtime by pass-cli run --env-file. This also covers identifying values that are not credentials but still should not sit in git — a real public IP, the tailnet name. Set those as TF_VAR_<name>=pass://....

A genuinely non-identifying constant that is also shared with other parts of the repo — the domain — is read straight from its committed source, config/domain/domain.env, as a local rather than duplicated into terraform.tfvars. See Domains.

State stays local and gitignored. tofu/**/.terraform/, tofu/**/*.tfstate* and tofu/**/crash.log are all excluded. A module’s minted credentials can sit in state in plaintext even when marked sensitive — that only suppresses console and plan output. Keep state on the operator machine. .terraform.lock.hcl is the provider version lockfile and is committed.

Verify provider resource and attribute names against current provider docs before the first apply.

Running a module

task tf:init [-- <module>]   # no secrets needed, provider download only
task tf:plan -- <module>
task tf:apply -- <module>

task tf:init with no module argument inits every module under tofu/, and runs as part of task ops:setup. plan and apply wrap pass-cli run --env-file secrets.env -- tofu <cmd>.

The pre-commit tofu-validate hook only runs fmt and validate, never init — a hook that touches .terraform.lock.hcl fails pre-commit’s own “did this hook modify a file” check. Run task tf:init once locally before committing. CI runs init as its own step first; see Checks and CI.

Modules

ModuleManages
bunnyPublic DNS records in the existing Bunny DNS zone
oidcPocket ID OIDC clients, writing the minted secret into OpenBao
tailscaleThe tailnet policy file, including the ip-in-ip rule the pod overlay depends on