Scout — proof collection (Trust Radar)¶
Beyond scanning, Scout gathers proof attestations: local, on-host evidence
the Hub uses for Trust Radar. Every attestation carries a status from a small
vocabulary — proven, partial, conflict, missing — and Scout filters out
any attestation whose kind isn't in the wire vocabulary before publishing
(a soft guard against collector drift, proof_collectors.go:20).
There are exactly four proof kinds. Each is fed by one or more collectors.
Read the maturity notes
Several collectors are narrower than their name suggests. This page is deliberately honest about what is and isn't proven, because the distinctions matter when you rely on the evidence. Everything below describes Scout on Linux x86-64 — the supported platform (see Install → Supported platforms).
local_trust_store_membership¶
"Is this CA certificate present in a trust store on this host?" Two
sub-collectors feed it, both using the same membership test: parse the
store, keep certs where x509.Certificate.IsCA == true, fingerprint by SHA-256.
This is a presence scan, not a trust-chain proof
Membership means "a CA-flagged cert sits in a known store path" — it does not verify the anchor is self-signed, that it actually roots any chain, or that the OS/app truly consults that store at runtime. It reads the files the OS would build trust from; it doesn't ask the OS "do you trust this?"
| Sub-collector | Inspects |
|---|---|
| OS store | The distro CA bundles (/etc/ssl/certs/ca-certificates.crt, /etc/pki/tls/certs/ca-bundle.crt, /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem, /etc/ssl/ca-bundle.pem) + anchor dirs (/etc/ssl/certs, /etc/pki/ca-trust/source/anchors, /usr/local/share/ca-certificates) — the Debian/Ubuntu, RHEL/Fedora, and SUSE layouts. The agent flag --trust-store-path <abs-path> (repeatable) adds an extra bundle file or anchor directory on top of these defaults; a path already in the defaults is deduped, and anchors found via a configured path carry source_kind: operator_configured in their metadata. PEM / raw-DER / JKS. |
| Application stores | Java cacerts at the JDK default paths, app-configured Java truststores (javax.net.ssl.trustStore-style directives parsed out of Tomcat server.xml, Kafka/Elasticsearch/Logstash configs, systemd units, /etc/default, /etc/sysconfig), service-mesh bundles (Istio/Linkerd/SPIFFE), and CA-file directives parsed out of nginx/Apache/HAProxy/Caddy/Traefik/Envoy configs. |
Gaps worth knowing:
- A missed path yields no attestation. The default OS-store paths are
probed silently: one that is absent produces no attestation, not an error. A
CA bundle at a non-standard location (a hardened image, a container with a
custom trust path) is invisible until an operator declares it with
--trust-store-path. A configured path that is missing or unreadable at collection time logs a WARN naming the path (a bad configured path is a signal, an absent default is not). - PKCS12/JCEKS Java stores are unsupported (no parser). An unreadable Java
store emits an explicit
missingproof; an unreadable nginx/Apache/etc. trust-store reference emits nothing — a silent gap, not a negative proof. - Config discovery is glob-based on conventional paths, not real parsing —
no
nginx includeresolution, no YAML/Caddyfile grammar. Non-standard layouts are invisible.
installed_vs_served¶
"Does the cert configured/installed here match what's actually served on the wire?" Two collectors emit this kind:
- Generic scan-vs-local — cross-references live scan fingerprints against
filesystem-discovered certs.
provenwhen fingerprints agree,conflictwhen they differ,partialwhen only one side is present. - Server-binding (nginx / Apache / HAProxy / Caddy / Traefik / Envoy) —
reads the configured leaf cert file off disk, fingerprints it, and compares
to the live scan for the name-matched vhost. Never reads private-key material
(
private_key_material_collected: false). Config paths are the conventional/etclocations for each server.
Coverage gaps
Server-binding proofs don't cover Tomcat/Kafka/Elasticsearch/Logstash's own served certs (those apps are only scanned for trust-store references), and there is no Kubernetes / cert-manager collector anywhere in Scout — if the product surfaces K8s cert-manager evidence, that lives outside Scout.
local_renewal_controller¶
"Which local automation renews this cert, and via which CA?" It parses
certbot (/etc/letsencrypt/renewal/*.conf), acme.sh, lego (path
heuristic), and generic systemd/cron definitions, and matches each to a
discovered cert. If two different controllers claim the same cert, all are
downgraded to conflict. Every discovered cert gets at least one attestation —
an explicit missing if no controller is found. Full 4-state vocabulary.
key_custody_metadata¶
"Is there a plausible private-key file beside this cert, and what's its file hygiene?"
This never reads keys and never checks pairing
Despite the name, this collector is filename-convention guessing +
stat() — it records the candidate key path, octal permission mode, a
coarse permission summary, symlink flag, size, and owner/group UID/GID. It
explicitly sets private_key_material_collected: false,
key_match_validated: false — it does not open the key or verify it
pairs with the cert. Describe it as "candidate key-file discovery + file
hygiene," not "key custody verification."
Maturity at a glance¶
| Collector | Kind | Maturity |
|---|---|---|
| Generic installed-vs-served | installed_vs_served |
Live |
| Server binding | installed_vs_served |
Live |
| OS trust store | local_trust_store_membership |
Live |
| Application trust store | local_trust_store_membership |
Live |
| Renewal controller | local_renewal_controller |
Live |
| Key custody metadata | key_custody_metadata |
Live |