Configuration Bundles
A configuration bundle is a reusable set of environment variables, mounted files and run hooks that runs receive when the bundle is attached to a stack. Keep shared configuration, such as provider settings or a .terraformrc, in one bundle and attach it to every stack that needs it.
Bundles belong to a space. Creating, editing and deleting bundles and their content requires the Admin role; attaching and detaching them on a stack requires Write.
What a bundle holds
- Environment variables: key, value and an optional description. A variable marked Secret has its value hidden in the UI and in API responses.
- Mounted files: a path relative to the run workspace (for example
certs/ca.pem; a leading/is dropped and..is refused), the content and an optional description. A path undersource/lands next to your Terraform code in the project root, sosource/backend.tfis readable with Terraform'sfile(). A file can also be marked Secret, which hides its content the same way. - Hooks: shell commands run before or after init, plan and apply in every stack the bundle is attached to, such as a scanner after the plan. See Run Hooks.
- Auto-attach labels: stack labels the bundle attaches itself to. See Attaching by label.
Reserved variables. Do not set TF_DATA_DIR, HOME, TF_CLI_CONFIG_FILE, TF_PLUGIN_CACHE_DIR, TF_CLI_ARGS or the other variables the worker owns. Zenfra stores the variable, but any run that receives it fails before execution with ENV_POLICY_REFUSED. TF_VAR_* and TF_WORKSPACE are fine. See Reserved variables.
Creating and editing a bundle
Bundles > Create Bundle asks for a Name, a Slug (auto-generated from the name; a unique identifier), the Space, an optional Description and optional Auto-attach labels. The bundle's detail page shows its auto-attach labels and has four tabs: Environment Variables (Add Variable), Mounted Files (Add File), Hooks and Used by, which lists the stacks the bundle is attached to by hand, with their priority (stacks it attaches to by label are not listed). Edit changes the description, space and auto-attach labels. Editing a variable, file or hook affects every attached stack on its next run; a queued run, or a run waiting for approval, that holds the bundle fails as stale (PLAN_STALE) when it next downloads its configuration, so start a new run.
Secret values
Zenfra never shows a secret's value again once it is saved, and editing the bundle keeps it:
- A secret sent back empty under the same key or path keeps its stored value, so saving a variable, file or hook leaves the other secrets as they are. When you edit a secret, leave its value empty to keep it, or type a new value to replace it. Spaces count as a value.
- A secret needs its value when it is new, when you change its key or path (that makes it a new secret), and when you turn Secret off (Zenfra does not reveal the stored value as plain text). Without it the save is refused and nothing changes.
- Deleting a variable or file deletes its value. Two variables with the same key, or two files with the same path, are refused.
- If someone else saved the bundle after you opened it, your save is refused rather than overwriting their change; reload the page and make your edit again.
Through the API, PUT /api/v1/bundles/{id}/content follows the same rules: send a secret with an empty value to keep it. A refusal answers 400 with the code secret_value_required or duplicate_entry and names the key or path. With the Terraform provider a secret's value always comes from your configuration, and an empty secret value or secret file content is refused at plan, or at apply when the value is only known then.
A bundle that is attached to a stack by hand cannot be moved to another space or deleted; detach it from all stacks first. Attachments by label do not block either.
Attaching bundles to stacks
Attach bundles in the stack wizard's Bundles step or under Bundles when editing the stack; changes made there are saved immediately.
A stack can attach a bundle from its own space, or from an ancestor space when every space on the way up has Inherit bundles from parent enabled. The picker offers exactly that set and searches by name, slug and description.
Each attachment has a priority. During the Preparing phase the worker applies the attached bundles in ascending priority order, so when two bundles set the same variable, the one with the higher priority number wins. Bundles attached by label are applied before all of them, so on the same variable or file path any bundle you attached wins over one attached by label. A stack's own environment variables override bundle variables.
Attaching by label
A bundle with auto-attach labels attaches itself to every eligible stack that carries one of those stack labels, with no attachment to manage. Use it for configuration every stack of a kind needs: give a scanner bundle the label prod, and every prod stack in the bundle's space, or in a space that inherits its bundles, runs the scanner.
- Auto-attach labels follow the stack label rules and match exactly. Set them in Create Bundle or Edit, or with
auto_attach_labelson the Terraform provider'szenfra_configuration_bundle. A bundle without them attaches only by hand. - A bundle attaches by label only where it could be attached by hand: to stacks in its own space, or in a descendant space when every space on the way down has Inherit bundles from parent enabled.
- A stack's Edit Stack > Bundles section lists these bundles under Attached by label, and the stack's Configuration tab marks them Auto (label). They cannot be detached; remove the label from the stack, or from the bundle's auto-attach labels. Attaching one by hand gives it a priority, and it then counts as attached by hand.
- Bundles attached by label have no priority. Among themselves they are applied, and their hooks run, in slug order.
- The set is worked out when a run is created and kept with it. Changing a stack's labels or a bundle's auto-attach labels affects later runs only. Every matching bundle attaches; there is no cap.
- Give a new bundle its variables, files and hooks before its auto-attach labels, so that no run starts with an empty bundle.