# Security and authentication

![Security and identity controls](../../docs/architecture/generated/security-controls.svg)

The diagram is a public-safe logical trust-boundary map; it contains no
identities, provider IDs, keys, tokens, or private addresses.

Its statement that Secret values are not backed up refers specifically to not
querying Kubernetes Secret objects or exporting ConfigMap values. Selected
workload specs retain literal fields, so an inline environment value, argument,
or annotation is not automatically scrubbed. The encrypted archive remains
sensitive until inspected.

- This implementation creates and stores no Google service-account key. A
  read-only 24 July 2026 inventory found no user-managed service-account key in
  this Google Cloud project; provider-managed key metadata is not presented as
  an operator-created credential.
- Projected k3s tokens use a provider-specific audience, one-hour expiry, the
  cluster issuer, and its public JWKS. Terraform grants
  `roles/iam.workloadIdentityUser` for the dedicated identities to the exact
  `backup` and `registry-auth` subjects used by this stack.
- Terraform grants the backup identity bucket-scoped create/get/list permissions
  and project log-writer permission; it does not grant bucket-object deletion.
- Terraform grants the registry identity read-only access to the reused private
  repository. The manifests configure a scheduled namespaced CronJob to patch
  only `gcp-artifact-registry` with a renewable OAuth pull token; the dynamic
  Secret is never stored in Git.
- The backup RBAC reads namespaces, nodes, selected workload kinds, and
  ConfigMap names/keys. On 16 July 2026, `kubectl auth can-i` confirmed that its
  ServiceAccount could not get Kubernetes Secrets.
- Terraform and the Kubernetes manifests set public access prevention, uniform
  bucket access, Google-managed encryption at rest, age client-side encryption,
  non-root pods, dropped capabilities, read-only roots, seccomp, and resource
  limits. NetworkPolicies deny ingress to the selected backup and registry-auth
  pods; they are not a namespace-wide default-deny policy.

Keep the age private identity mode 0600 outside the repository. Transfer it to
offline encrypted storage and repeat the decrypt-and-list inspection after
transfer. Public JWKS is not a secret but must be updated in Terraform when the
k3s signing key rotates.
