Kubernetes
A Sentinel can read certificate material from a Kubernetes cluster through the API server. You give it a read-only ServiceAccount, and the credentials stay on the Sentinel’s host. They are never sent to NoCert.
One Sentinel can read up to 16 clusters. It does not have to run inside them.
What it reads
Section titled “What it reads”Two passes per cluster, both read-only, no watch:
- Secrets of type
kubernetes.io/tls, listed with a server-side field selector. The API server applies the filter, so the list never returns another type. - Targeted reads of four service-mesh CA objects. Mesh CAs use their own types, so the filter above cannot see them. The list is exact:
istio-ca-secretandcacertsinistio-system,linkerd-identity-issuerand thelinkerd-identity-trust-rootsConfigMap inlinkerd. A cluster without a mesh returns nothing.
Kubernetes control-plane PKI does not come through here. A Sentinel running on a node picks it up with its filesystem scan, from /etc/kubernetes/pki/ and the k3s and RKE2 directories.
What leaves the cluster
Section titled “What leaves the cluster”The certificates, and enough to say where each came from: your cluster name, the namespace, the object name and type, the data key, and a flag when cert-manager manages the Secret.
Private keys do not leave. Kubernetes offers no field projection on Secret data, so a Secret arrives whole in the Sentinel’s memory, tls.key included. Only the allowlisted keys are read back out of it: tls.crt, ca.crt, and the mesh CA certificates. The wire format has no field that could carry a private key, and the agent is open source, so you can check that rather than take our word for it.
1. Turn the scan on
Section titled “1. Turn the scan on”Kubernetes scanning is off by default, because it also needs credentials on the host. Open Sentinels, open the host that will read the cluster, and enable it there.
2. Create the reader
Section titled “2. Create the reader”On the same page, select Add cluster. The wizard builds the manifest and gives you a kubectl apply command to run.
It grants get and list on Secrets, and get on ConfigMaps, to a ServiceAccount in a dedicated nocert-sentinel namespace.
Cluster-wide is the default. Namespace-scoped access is also offered, and it comes with two conditions:
- You have to apply the namespace include list in NoCert. Without it the Sentinel keeps sweeping every namespace and RBAC denies the first sweep. The list applies to the whole Sentinel, not to one cluster, so applying it drops the out-of-scope findings of any other cluster that Sentinel reads.
- The mesh CA objects live in
istio-systemandlinkerd. Bind those namespaces too, or that second pass returns nothing.
3. Put the credentials on the host
Section titled “3. Put the credentials on the host”Run this as root on the Sentinel’s host:
install -d -o nocert-sentinel -g nocert-sentinel -m 0700 /etc/nocert-sentinel/k8s
kubectl -n nocert-sentinel get secret nocert-sentinel-reader-token \ -o jsonpath='{.data.token}' | base64 -d > /etc/nocert-sentinel/k8s/prod-tokenkubectl -n nocert-sentinel get secret nocert-sentinel-reader-token \ -o jsonpath='{.data.ca\.crt}' | base64 -d > /etc/nocert-sentinel/k8s/prod-ca.crt
chown nocert-sentinel:nocert-sentinel /etc/nocert-sentinel/k8s/prod-*chmod 0600 /etc/nocert-sentinel/k8s/prod-*4. Declare the cluster
Section titled “4. Declare the cluster”Add it to /etc/nocert-sentinel/config.yaml:
allow_kubernetes_scan: truekubernetes_clusters: - name: prod server: https://10.0.0.10:6443 ca_file: /etc/nocert-sentinel/k8s/prod-ca.crt token_file: /etc/nocert-sentinel/k8s/prod-tokenThe name tags every finding from this cluster. Use lowercase letters, digits, dots, dashes and underscores, up to 64 characters.
An existing kubeconfig works if its user carries an inline token or a client certificate:
kubernetes_clusters: - name: staging kubeconfig: /etc/nocert-sentinel/k8s/staging.kubeconfig context: stagingTwo things a kubeconfig may not do. Exec plugins are rejected, so one that shells out to aws eks get-token will not load: the Sentinel runs no external binary to obtain a credential. tokenFile is rejected too, because a kubeconfig chooses its own server and CA, and an arbitrary file path would let it send the contents of any readable file as a bearer token. Use token_file in config.yaml instead, as above.
Restart when you’re done:
sudo systemctl restart nocert-sentinel5. Check it worked
Section titled “5. Check it worked”The cluster appears on the Sentinel’s page with its state. Expect No sweep reported yet until the Sentinel next polls.
A cluster whose last complete sweep is older than twice the cadence shows as stale rather than green, so roughly two hours by default. NoCert can’t tell a slow Sentinel from a dead one, so it doesn’t guess.
| State | What it means |
|---|---|
| Access forbidden (RBAC) | The ServiceAccount lacks RBAC. Re-apply the RoleBinding or ClusterRoleBinding for this cluster. |
| Authentication failed | The token was rejected. It may have expired, so extract it again from the reader Secret. |
| Unreachable | The Sentinel’s host can’t reach the API server. Check the server URL and the network path. |
| Local config error | The credentials wouldn’t load. Check server, ca_file and token_file, or the kubeconfig. |
| Timed out | The API server didn’t answer in time. It may be overloaded, or the endpoint may be wrong. |
| Incomplete | The sweep hit its size limit. Narrow the namespaces, or split the clusters across Sentinels. |
| Not swept | An earlier cluster used up the sweep budget before this one was reached. |
| No longer reported | Renamed or removed from this Sentinel. Its findings stay until a complete sweep reconciles them. |
Turning it off
Section titled “Turning it off”Set allow_kubernetes_scan: false on the host and restart. The Sentinel then refuses the scan even when NoCert asks for it. Removing the entry from kubernetes_clusters has the same practical effect, and the cluster moves to No longer reported.