# Secrets

This page inventories every Secret CAPTF reads or writes: what it is named, which namespace it lives in, who creates and deletes it, what it contains, and whether it carries sensitive data. Read it before deciding who may read Secrets in a tenant namespace, or before writing a NetworkPolicy or admission policy that assumes only some Secrets matter. For what the runner’s own access to these Secrets means once a Job is running, see [Security model](<https://captf.io/docs/concepts/security-model/index.md>).

For how these Secrets are created, connected and deleted, with walkthroughs, see [Secret Management](<https://captf.io/docs/concepts/secret-management/index.md>).

> [!NOTE]
>
> **Before you begin**
>
> - `get` access to Secrets in the namespaces you administer, to inspect any of these.
> - Knowing which kind (`TerraformCluster`, `TerraformMachine` or `TerraformMachinePool`), object name or identity a Secret belongs to; several of the name patterns below embed one of these.

## Every Secret CAPTF reads or writes

| Name pattern | Namespace | Owner | Created / deleted | Contents | Sensitive |
| --- | --- | --- | --- | --- | --- |
| Identity’s source Secret (any name, `TerraformClusterIdentity.spec.secretRef`) | `secretRef.namespace`, any namespace | The operator | By the operator; CAPTF never creates, updates or deletes it, and removes any owner reference an older CAPTF version left on it | Cloud credentials (arbitrary keys and values, provider SDK conventions or file contents) | Yes |
| `captf-creds-<identity>` (mirror) | Each namespace `allowedNamespaces` permits and that has resolved the identity | The `Terraform*` object(s) using the identity there, as non-blocking owner references | Created the first time an object in the namespace resolves the identity; rewritten whenever the source Secret’s data changes; deleted when the namespace stops being allowed, or when its last owning object is removed | A byte-for-byte copy of the source Secret’s data | Yes |
| `captf-inputs-c-<name>`, `captf-inputs-m-<name>`, `captf-inputs-mp-<name>` (durable inputs) | The object’s namespace | The `TerraformCluster`, `TerraformMachine` or `TerraformMachinePool` itself | Created before the object’s first Job; rewritten on every reconcile that re-renders inputs; deleted once the object’s state and infrastructure are gone | The rendered root module and tfvars, plus the pinned image, image digest and identity | Yes |
| `captf-run-<job>` (per-run) | The object’s namespace | The Job | Created just before the Job’s pod starts, from that reconcile’s rendered inputs; deleted once the controller has read the finished Job’s result | The same rendered root module and tfvars the Job runs with | Yes |
| `tfstate-default-<suffix>` and its `-part-N` chunks (state) | The object’s namespace | Unowned until the first successful apply, then the object, as a non-blocking owner reference | Created by the Terraform/OpenTofu Kubernetes state backend itself, not by CAPTF; deleted by CAPTF after a successful destroy, or immediately on deleting an object that never applied | The compressed Terraform state, plus the backend’s own workspace labels | Yes |
| `captf-state-backup-<suffix>-<serial>` and its `-part-N` chunks (state backups) | The object’s namespace | The `Terraform*` object, as a non-blocking owner reference (never the state) | Created after a reconcile observes a state serial not backed up yet; pruned to a configured retention on the same pass; never deleted by the destroy cleanup above | A verbatim copy of the state Secrets they were taken from, at that serial | Yes |
| Bootstrap data Secret (any name, `Machine.spec.bootstrap.dataSecretName` or `MachinePool.spec.template.spec.bootstrap.dataSecretName`) | The Machine’s or MachinePool’s namespace | The bootstrap provider (for example a `KubeadmConfig`), not CAPTF | By the bootstrap provider; CAPTF only reads it, uncached, and never labels, updates or deletes it | The bootstrap data (`value`) and its format (`format`) | Yes |
| `spec.variablesFrom` source (any name, labeled `captf.io/variables=true`) | The object’s namespace | The operator | By the operator; CAPTF only reads it, and only while the label is present — an unlabeled Secret counts as missing | Arbitrary keys treated as module variable values | Yes |
| Image pull secret (any name, named in `spec.jobs.imagePullSecrets`) | The object’s namespace | The operator | By the operator; for a `TerraformCluster`, `TerraformMachine` or `TerraformMachinePool`, CAPTF only references its name on the Job’s pod, never reading or writing its contents. For a `TerraformMachineTemplate`, CAPTF also reads its own pull Secrets’ contents to authenticate the image inspection that resolves capacity, but never writes them | A `kubernetes.io/dockerconfigjson` registry credential | Yes |
| `captf-webhook-service-cert` (webhook serving certificate) | The provider’s namespace | cert-manager, through its `Certificate` object | By cert-manager, on issuance and renewal; CAPTF never creates, reads or deletes it | A TLS key pair and CA bundle for the admission webhook | Yes |

A name pattern that would exceed the 253-character Secret name limit — the mirror and the durable inputs Secret, both built from a user-chosen name — is shortened to its prefix plus a hash, still deterministic and unique.

## What the manager caches

The manager’s main cache holds only Secrets labeled `captf.io/managed=true`: credential mirrors, durable and per-run inputs, state and state backups — the five Secrets above that carry that label, whether CAPTF or the state backend created them. A second, separate cache backs `spec.variablesFrom` watches; it holds Secrets (and ConfigMaps) labeled `captf.io/variables=true`, with their data stripped out before they are stored, so no variable value ever sits in memory there. Everything else — the identity’s source Secret, bootstrap data, image pull secrets, and a `spec.variablesFrom` Secret’s actual content when it is resolved — is read directly from the API server on demand and never watched.

## What never enters logs or status

The durable and per-run inputs Secrets carry bootstrap data and module variable values in clear by design, and CAPTF never logs their data. State and its backups are read the same way: never logged.

> [!WARNING]
>
> **Sensitive variable values are still written in clear into the inputs and state**
>
> A `spec.variablesFrom` value marked sensitive is redacted from the Job’s own plan and apply output and from the controller’s trace-level logs, but that redaction does not reach the Secrets in this table: like every other input, the value is still written in clear into the durable and per-run inputs Secrets and into the state.

This is a separate guarantee from what CAPTF keeps out of `status` and events, which never carry Secret contents at all; see [what CAPTF keeps out of status, events and logs](<https://captf.io/docs/concepts/security-model/#what-captf-keeps-out-of-status-events-and-logs>).

> [!NOTE]
>
> **See also**
>
> - [Security model](<https://captf.io/docs/concepts/security-model/index.md>)
> - [RBAC](<https://captf.io/docs/operator-guide/rbac/index.md>)
> - [Identities and Credentials](<https://captf.io/docs/user-guide/identities/index.md>)
> - [Job Inputs](<https://captf.io/docs/concepts/inputs/index.md>)
> - [Terraform State](<https://captf.io/docs/concepts/state/index.md>)
> - [Module Variables](<https://captf.io/docs/user-guide/variables/index.md>)
