Skip to content

Network and filesystem scans

A Sentinel runs four kinds of scan. Each one is requested by NoCert; none runs on a schedule the Sentinel keeps for itself.

Open Sentinels, open the host, and turn each scan on or off there. The host can also refuse a scan outright with one of the kill switches in its config file.

The Sentinel opens a TLS connection to the addresses in the ranges you gave it, on the ports you chose, and keeps what the host presents.

One sweep probes at most 100,000 address and port pairs. With the default port list that is about 5,200 addresses, so a range wider than a /19 is covered by a random sample that rotates from one sweep to the next rather than in a single pass.

Set the ranges per Sentinel. At enrollment the Sentinel reports the subnets of its own interfaces, and NoCert offers those as suggestions.

The ranges drive the periodic sweep. On top of that, the Sentinel probes the hosts NoCert already monitors for you, whether or not you set a range.

Rules on the ranges:

  • IPv4 only.
  • No broader than /16. A /8 is rejected when you save it, because the Sentinel would not expand it anyway.
  • 64 ranges per Sentinel at most.

Ports are an organization-wide default, set in Settings → Scan Configuration and overridable per Sentinel. The default list covers 443, 636, 2379, 2380, 3389, 4646, 5000, 5671, 5986, 6443, 8006, 8200, 8443, 8501, 9000, 9001, 9200, 9443 and 10250, so Kubernetes, Vault, Consul, etcd, MinIO, Proxmox and Elasticsearch are all reached without you listing them.

NoCert asks for a full sweep every 2 hours by default.

The filesystem, local and Kubernetes scans share a second cadence, hourly by default.

The Sentinel looks for certificate files on the host’s disk, two ways.

First, it walks well-known directories:

/etc/letsencrypt/live/
/etc/docker/certs.d/
/usr/local/share/ca-certificates/
/etc/kubernetes/pki/
/var/lib/kubelet/pki/
/var/lib/rancher/k3s/server/tls/
/var/lib/rancher/rke2/server/tls/

Second, it reads configuration files under /etc and follows the certificate paths they reference. This is what finds a certificate in a directory nobody would guess, without needing a parser per application.

The walk leaves out the system trust store, which holds public CAs rather than yours. A configuration file that points into /etc/pki/ca-trust/, /etc/ca-certificates/ or /usr/share/ca-certificates/ is skipped too, as are /etc/ssl/certs/ca-certificates.crt and /etc/ssl/certs/ca-bundle.crt. Otherwise one reference would drag hundreds of CA files through every sweep for nothing.

Whatever the walk turns up, only leaf certificates become findings. CA material read from disk is used to resolve chains and never appears in the Sentinel’s Filesystem list, which is why a directory of local CAs, or an intermediate sitting inside a fullchain.pem, shows nothing there.

Secret volumes mounted into pods under /var/lib/kubelet/pods/ are excluded as well, because they hold private keys. The public half of those certificates comes from the Kubernetes scan instead.

When a key file sits next to a certificate under a matching name (cert.crt and cert.key, private/cert.key, or a cert.pem whose first kilobyte carries a PRIVATE KEY header), the Sentinel checks its mode. If it is looser than 0600, meaning any group or other bit is set, the finding carries insecure_private_key_permissions.

That is the only warning the filesystem scan produces. The Sentinel never sends the key and never sends its path. Only the flag travels.

The match is by filename. Let’s Encrypt is the common case, where privkey.pem never matches fullchain.pem, so a host with no warning may still have a world-readable key.

The Sentinel reads /proc/net/tcp and /proc/net/tcp6 to list the host’s own listening sockets, then opens a TLS connection to each and records the certificate actually served. It stops at 256 ports and marks the sweep incomplete beyond that.

Those files only ever show the reader’s own network namespace. A Sentinel running inside a container sees that container’s listeners and nothing else, and a published container port is a forwarding rule rather than a listener, so it never appears. Run the Sentinel on the host, or with host networking, or this scan finds nothing worth having.

This is the scan that catches a renewal that never took effect: the new certificate is on disk, the service was never reloaded, and it is still presenting the old one.

Every listening port is probed except a skip list. That list holds the ports that are plaintext or STARTTLS by default, so the Sentinel does not write protocol errors into your own service logs: FTP, SSH, Telnet, SMTP on 25 and 587, DNS, POP3, IMAP, LDAP, XMPP, MySQL, PostgreSQL, Redis, Kafka, memcached and MongoDB.

Everything else gets a TLS handshake, including ports serving something that isn’t TLS at all.

Redis and MongoDB can serve TLS on their usual port. The Sentinel misses those cases here on purpose, and the network or filesystem scan still surfaces the certificate.

The Sentinel reads TLS Secrets through the cluster API server, using credentials that stay on its host. See Kubernetes.

The Sentinel has no cron of its own. NoCert tracks when each one last swept and hands out the next task when it is due. Change a range or a cadence in the web app and it applies without touching the host.

It also means a Sentinel that goes Stale after 7 minutes, then Offline after 30, has stopped asking for work. Check the service before you assume the network changed. A Sentinel you deactivated in NoCert also reads as Offline, whatever the host is doing.

One you have just enrolled shows Enrolled, never reported until its first poll lands. That is the state to expect right after an install, and systemctl status nocert-sentinel on the host is the next step.