Labels and Annotations Reference
Kloak uses Kubernetes labels and annotations to control which secrets are protected, which pods are intercepted, and which hosts are allowed for secret transmission.
Overview
| Name | Type | Applies To | Description |
|---|---|---|---|
getkloak.io/enabled | Label | Secret | Enables Kloak protection for this secret. Triggers shadow secret creation. |
getkloak.io/enabled | Annotation | Secret | Alternative to label. Enables Kloak protection for this secret. |
getkloak.io/enabled | Label | Pod | Enables Kloak for this pod. The webhook's objectSelector matches pods with this label. |
getkloak.io/enabled | Annotation | Pod | Injected by the webhook on mutated pods. Read by the controller to attach eBPF uprobes. Do not set manually. |
getkloak.io/enabled | Label | Namespace | Enables Kloak for all pods in this namespace. The webhook's namespaceSelector matches namespaces with this label. |
getkloak.io/hosts | Label | Secret | Comma-separated list of allowed TLS destination hostnames. |
getkloak.io/port | Label | Secret | Allowed destination port for secret transmission (e.g., 443). If omitted, all ports are allowed. |
getkloak.io/managed | Label | Secret (shadow) | Automatically set by Kloak on shadow secrets. Do not set manually. |
getkloak.io/owner | Label | Secret (shadow) | Name of the original secret. Automatically set by Kloak. Do not set manually. |
Detailed Reference
getkloak.io/enabled
Controls whether Kloak processes a resource. The value must be exactly "true" (string).
On Secrets (Label or Annotation)
When set on a Secret, the SecretReconciler:
- Creates a shadow secret named
<secret-name>-kloakwithkloak:<ULID>placeholder values - Stores the ULID-to-real-value mapping in the in-memory store
- Sets up an
OwnerReferenceso the shadow is garbage collected when the original is deleted
apiVersion: v1
kind: Secret
metadata:
name: my-api-key
labels:
getkloak.io/enabled: "true"
type: Opaque
data:
key: bXktc2VjcmV0LXZhbHVlTIP
Both labels and annotations are checked (secret.Labels["getkloak.io/enabled"] == "true" || secret.Annotations["getkloak.io/enabled"] == "true"). Use labels for consistency with the other Kloak resources.
To disable protection, remove the label:
kubectl label secret my-api-key getkloak.io/enabled- -n my-namespaceThe shadow secret will be automatically deleted and storage mappings cleaned up.
On Pods (Label)
When set as a label on a Pod (typically via the pod template in a Deployment/StatefulSet/DaemonSet), the webhook's objectSelector matches the pod and processes it:
- Rewrites Secret volume references to point to shadow secrets
- Injects the
getkloak.io/enabledannotation (read by the controller) - Rejects the pod if any shadow secret is missing (fail-closed)
metadata:
labels:
getkloak.io/enabled: "true"WARNING
Pod enablement requires a label, not an annotation. The webhook uses Kubernetes objectSelector to match pods, which only works with labels.
On Namespaces (Label)
When set on a Namespace, two things happen:
- Webhook scope: The
MutatingWebhookConfigurationhas anamespaceSelectorthat matches namespaces with this label. All pods created in this namespace are sent to the webhook. - Enablement inheritance: All pods in this namespace are treated as Kloak-enabled, even without an explicit pod label.
kubectl label namespace my-app getkloak.io/enabled=trueDANGER
Labeling a namespace enables Kloak for every pod in that namespace. Make sure all applications in the namespace are compatible (see Supported Runtimes). Pods using unsupported TLS stacks will fail to have uprobes attached, which is logged as an error but does not block the pod.
getkloak.io/hosts
Restricts which TLS destination hostnames are allowed to receive the real secret value. Applied as a label on Secrets.
Type: Label Applies to: Secret Format: Comma-separated hostnames (no wildcards, no ports)
metadata:
labels:
getkloak.io/enabled: "true"
getkloak.io/hosts: "api.stripe.com"Multiple hosts:
metadata:
labels:
getkloak.io/enabled: "true"
getkloak.io/hosts: "api.stripe.com,dashboard.stripe.com"Behavior:
- If the label is present: only connections to the specified hostname(s) receive the real value. All other destinations see the
kloak:<ULID>placeholder. - If the label is absent or empty: the secret is allowed for all destinations (wildcard).
WARNING
Currently, only the first hostname in the comma-separated list is enforced in the eBPF map (spinningfactory/kloak#102).
TIP
Hostnames are matched exactly (case-sensitive, no wildcards). Use the exact hostname your application connects to. For example, use api.stripe.com, not *.stripe.com or stripe.com.
Hostname length limit: 64 characters. Hostnames longer than 64 characters are truncated in the BPF map.
getkloak.io/port
Restricts which destination port is allowed to receive the real secret value. Applied as a label on Secrets.
Type: Label Applies to: Secret Format: Port number as a string (e.g., "443")
metadata:
labels:
getkloak.io/enabled: "true"
getkloak.io/hosts: "api.stripe.com"
getkloak.io/port: "443"Behavior:
- If the label is present: only connections to the specified port receive the real value.
- If the label is absent or empty: the secret is allowed for all ports (wildcard).
getkloak.io/managed
Automatically applied by Kloak to shadow secrets. Indicates that the secret is managed by Kloak and should not be manually edited.
Type: Label Applies to: Secret (shadow) Value: "true"
# Automatically set -- do not create manually
metadata:
name: my-api-key-kloak
labels:
getkloak.io/managed: "true"
getkloak.io/owner: "my-api-key"DANGER
Do not manually create or modify secrets with getkloak.io/managed=true. They are fully managed by the SecretReconciler and will be overwritten on the next reconciliation cycle.
getkloak.io/owner
Automatically applied by Kloak to shadow secrets. Contains the name of the original secret that this shadow was created from.
Type: Label Applies to: Secret (shadow) Value: Name of the original secret
This label is informational and used for operational visibility (e.g., listing which shadow secrets exist for a given original).
Enablement Precedence
The webhook checks for enablement in the following order. The first match wins:
- Pod label
getkloak.io/enabled: "true"-- most specific - Namespace label
getkloak.io/enabled: "true"-- applies to all pods in namespace - If neither matches, the pod is not processed by Kloak
Pod label? ──yes──▶ Enabled
│ no
▼
Namespace label? ──yes──▶ Enabled
│ no
▼
Not enabledTIP
Workload-level inheritance (Deployment, DaemonSet, StatefulSet labels) is not supported. Use pod template labels or namespace labels instead.
Quick Reference
Enable Kloak for a secret:
kubectl label secret my-secret getkloak.io/enabled=true -n my-namespaceEnable Kloak for a namespace:
kubectl label namespace my-namespace getkloak.io/enabled=trueAdd host filtering:
kubectl label secret my-secret getkloak.io/hosts=api.stripe.com -n my-namespaceDisable Kloak for a secret:
kubectl label secret my-secret getkloak.io/enabled- -n my-namespaceCheck if a pod was mutated:
kubectl get pod <pod-name> -n my-namespace -o jsonpath='{.metadata.annotations.getkloak\.io/enabled}'List all shadow secrets:
kubectl get secrets -l getkloak.io/managed=true --all-namespacesFind the shadow for a specific secret:
kubectl get secrets -l getkloak.io/owner=my-secret -n my-namespace