Credentials¶
A Job never reads the operator’s credentials Secret. The manager copies it into the object’s namespace, and the Job gets that copy. This page covers the pieces and how a credential change propagates. For creating an identity and choosing its namespaces, see Identities and Credentials.
The pieces¶
- The source Secret. Any name, in any namespace, created and owned by the operator. CAPTF never writes it. It carries no move label, so
clusterctl movedoes not carry it (seeclusterctl move). - The
TerraformClusterIdentity. A cluster-scoped object that names the source Secret inspec.secretRefand the namespaces that may use it inspec.allowedNamespaces. It carries no credential data. - The mirror,
captf-creds-<identity>, in each allowed namespace where an object uses the identity. It is anOpaqueSecret with a copy of the source’s data and:- labels
captf.io/mirrored=trueandcaptf.io/managed=true; - annotations
captf.io/source-hash(a SHA-256 over the source’s data) andcaptf.io/identity(the identity’s name); - one non-controller owner reference per
Terraform*object that uses it, withblockOwnerDeletionunset. A reference to an earlier UID of an object is replaced on its next reconcile.
- labels
A name over 253 characters is shortened to captf-creds- and 16 hex characters of a hash.
Who may point an identity at a Secret¶
Creating an identity, changing spec.secretRef, or widening spec.allowedNamespaces makes the admission webhook run a SubjectAccessReview: the requesting user must be able to get the named Secret. An unset allowedNamespaces allows no namespace, and {} is rejected as ambiguous; selector: {} allows every namespace. Without the check, a role that may manage identities but not read Secrets could use an identity to have the manager mirror a Secret into a namespace it can read. See Identities and Credentials.
When the mirror is written¶
The manager makes sure the mirror is current:
- on every reconcile of every non-deleting object that uses the identity;
- just before it creates a deletion Job, so a destroy has credentials.
Each time, it reads the source Secret uncached, hashes its data and compares the hash with the mirror’s captf.io/source-hash. If they differ it rewrites the mirror’s data. That is the only way a rotation reaches the mirror.
Rotation¶
Nothing watches the source Secret. A rotated credential reaches the mirror on the next reconcile of any object that uses it, which is bounded by the manager’s --sync-period (default ten minutes). A Job that is already running keeps the credentials it started with; the next Job gets the new ones. The identity’s own controller only reports status: it re-reads the source every five minutes to set the identity’s Ready condition and status.namespaces, and does not copy anything.
Revocation¶
If the identity stops allowing a namespace, because you narrowed allowedNamespaces or relabeled the namespace, the manager deletes that namespace’s mirror on the next reconcile and the objects there report IdentityAllowed=False/NamespaceNotAllowed. A destroy that needs the identity then waits with ApplyJobSucceeded=False/IdentityNotAllowed and requeues; the way out is to allow the namespace again or to abandon the infrastructure.
When the last object using the mirror is removed, cleanup removes its own owner reference and deletes the mirror. You cannot delete an identity while any object uses it: the delete webhook refuses until status.namespaces is empty.
Conflicts¶
If a Secret named captf-creds-<identity> already exists and is not a mirror, the manager never overwrites it. It reports CredentialsMirrored=False with MirrorFailed. Rename or remove the Secret that is in the way.
Delivery to the runtime¶
The Job gets the mirror two ways at once:
envFrom, so every key becomes an environment variable;- a read-only mount at
/var/run/captf/credentials, mode0440, one file per key.
Every key in the source Secret reaches the Terraform process
Anything in the source Secret reaches the Terraform process as an environment variable, whether or not the module uses it.
The runner removes keys starting with TF_ or KUBE_ from the environment, except the three the Job sets itself (TF_IN_AUTOMATION, TF_INPUT and KUBE_NAMESPACE). Otherwise a key such as TF_WORKSPACE or TF_VAR_x could move the state or override the rendered inputs. A dropped key is still present as a file. More on the environment is in Inside the Job and the runtime environment.