lookout state edges
Verify every dependency edge of one workload — ConfigMap/Secret keys, imagePullSecrets, Service selectors and endpoints, Ingress backends and class, StatefulSet governing Service and volume classes, ServiceAccount/RBAC references, TLS expiry — reporting only the broken ones. —workload also accepts Service/<namespace>/<name> to enter from the service side, which is the direction the evidence arrives from when a service has no endpoints: it reports that service’s selector, endpoints, ingresses and certificates, and names the workload the selector was probably meant for.
MCP tool: k8s_state_edges (MCP profile: triage)
lookout state edges [flags]| Flag | Type | Default | Meaning |
|---|---|---|---|
--cert-warn | duration | 720h | report TLS certificates expiring within this window |
Common flags (every lookout command)
Section titled “Common flags (every lookout command)”| Flag | Type | Default | Meaning |
|---|---|---|---|
--namespace | string | — | limit the scan to one namespace |
-A | bool | — | scan all namespaces |
--workload | string | — | target one workload as <Kind>/<namespace>/<name>, e.g. Deployment/prod/api |
--since | duration | — | how far back to look (0 = command default) |
--format | string | logfmt | output format: logfmt|json (one record per line either way) |
--timeout | duration | 10s | abort the invocation after this long (exit 1) |
--kubeconfig | string | — | path to a kubeconfig file, instead of $KUBECONFIG / ~/.kube/config |
--context | string | — | kubeconfig context to read, instead of its current-context. Selects a cluster for THIS invocation only — nothing is written back — so concurrent invocations can target different clusters. Reported as context=<name> in the summary line |
--exemptions | string | — | path to a git-reviewed exemption file (YAML); covered findings are ANNOTATED with their reason and expiry and counted as exempt=<n> in the summary, never dropped |
Finding kinds
Section titled “Finding kinds”Every kind= this command can emit, and the severities it carries them at. Nothing else appears in its output; a kind absent from a run means the check looked and found nothing. See the finding-kind glossary for the whole vocabulary.
| Kind | Severity | Claim |
|---|---|---|
edge.missing_ref | critical | a referenced ConfigMap, Secret, ServiceAccount, TLS secret, IngressClass, StorageClass, or governing Service does not exist |
edge.missing_key | critical | the referenced key is absent from an existing ConfigMap/Secret |
edge.invalid_ref | warning | the referenced object exists but is the wrong type to serve the reference |
edge.unclassed | warning | the Ingress names no class and no IngressClass declares itself the cluster default — no controller will claim it |
edge.selector_empty | critical | a Service selector selects zero pods, so the service routes nowhere |
edge.selector_unready | critical, warning | the Service selects pods but some are not Ready; critical when none are |
edge.endpoints_missing | critical | a selecting Service has no EndpointSlices at all |
edge.endpoints_orphaned | warning | an endpoint targetRef names a pod that no longer exists |
edge.endpoints_unready | critical, warning | the endpoint ready-count disagrees with the selected pods (stale or lagging slices); critical at zero ready |
edge.backend_missing | critical | an Ingress backend service, or the port it names, does not exist |
edge.cert_expired | critical | a TLS certificate’s NotAfter is in the past |
edge.cert_expiring | warning | a TLS certificate expires within —cert-warn |
edge.cert_invalid | warning | tls.crt is missing or unparseable, or the secret is not kubernetes.io/tls |
edge.rbac_dangling | warning | a (Cluster)RoleBinding for the workload’s ServiceAccount points at a missing (Cluster)Role |
Output fields
Section titled “Output fields”Beyond the shared envelope fields (kind, severity, namespace, kind_of_object, name, reason, message, fingerprint, exempt_reason, exempt_expires):
| Field | Meaning |
|---|---|
workload | the target the edges were traced from as <Kind>/<namespace>/<name>, stamped on every finding — a workload, or the Service itself when entered from the service side |
likely_workload | on a Service-entry edge.selector_empty: the workload in that namespace whose pod labels best fit the broken selector, i.e. the one it was probably meant to select. Absent when two workloads fit equally well, because then naming one would be a guess |
pods | how many of the workload’s pods carry the broken reference |
container | container declaring the broken env/envFrom reference |
env | environment variable whose valueFrom reference is broken |
volume | pod volume, or StatefulSet volumeClaimTemplate, whose reference is broken |
key | the referenced key that is missing from the ConfigMap/Secret |
selector | the Service label selector under scrutiny |
selected | pods the Service selector currently selects |
ready | ready count (selected pods or serving endpoints, per finding kind) |
endpoints | total endpoints across the Service’s EndpointSlices |
slices | how many EndpointSlices back the Service |
service | the Service a slice, Ingress backend, or StatefulSet serviceName refers to |
pod | pod named by an orphaned endpoint targetRef |
subject | TLS certificate subject (CN when set); never key material |
not_after | TLS certificate NotAfter, RFC 3339 |
days_left | whole days until NotAfter (negative = expired) |
via | how the broken reference is reached from the workload: mount, ingress, or imagePullSecret |
ingress | Ingress referencing the TLS secret, or the unserved Ingress itself |
host | Ingress rule host of the broken backend (empty for the default backend) |
path | Ingress rule path of the broken backend |
port | Service port (name or number) the Ingress backend asks for |
service_account | ServiceAccount the RBAC finding is about, or the one contributing an imagePullSecret |
role_ref | dangling roleRef as <Kind>/<name> |
Output contract
Section titled “Output contract”Output: one finding per line (logfmt; —format=json for one JSON object
per line), keys in fixed order; healthy resources emit nothing. The final
line is always the summary: scanned=
Examples
Section titled “Examples”lookout state edges --workload=Deployment/prod/apilookout state edges --workload=Pod/prod/api-6d5f8c-x2v9k --format=jsonlookout state edges --workload=StatefulSet/db/postgres --cert-warn=336hlookout state edges --workload=Service/prod/api