Surveyors
On this page
Surveyors discover your app's surface and return Saga fragments, so the
descriptor can write itself. Run them with
draugr survey.
Why discovery exists
The honest problem with a descriptor is the first one: writing it. A platform team with sixty services is not going to hand-type sixty components, and a hand-typed list is out of date the week after it's written. A service is added, an image is retagged, a namespace is split.
Discovery inverts that. The environment already knows what is running; a surveyor reads it and produces the components, so the descriptor starts complete and stays that way by being re-run.
Built-in surveyors
| Command | Discovers | Auth |
|---|---|---|
draugr survey k8s images | Unique container images running in a cluster or namespace, with their digests | Ambient kubeconfig (KUBECONFIG, ~/.kube/config, or in-cluster) |
draugr survey k8s cluster | The cluster itself, as a component's kubernetes: entry | Ambient kubeconfig |
draugr survey github repos | Repositories in a GitHub organization | GITHUB_TOKEN, or a token in scope config |
draugr survey gitlab projects | Projects in a GitLab group, subgroups included | GITLAB_TOKEN, or a token in scope config |
draugr survey azure repos | Git repositories in an Azure DevOps organization or project | AZURE_DEVOPS_EXT_PAT |
Each surveyor is a subcommand, so its options live with it. --namespace belongs to k8s images
and cannot be handed to github repos to be quietly ignored.
draugr survey github repos --org my-org -o draugr.saga.yaml
draugr survey k8s images --namespace prod -o draugr.saga.yaml
draugr survey k8s cluster --context prod -o draugr.saga.yaml
# Several namespaces, one component each
draugr survey k8s images --namespace payments --namespace checkout -o draugr.saga.yaml
A namespace is a component. --namespace repeats, and each one is surveyed on its own terms:
its component is named after it, and its exposure is proposed from its own topology. Naming none
discovers the whole cluster as a single component with no exposure proposed, because one exposure
covering everything running anywhere in a cluster would not mean anything.
k8s images and k8s cluster read the same cluster but describe different things, and are
deliberately separate: the images are the application, the cluster is what it runs on, and they
will differ in criticality. A surveyor named for images that also emitted an infrastructure
component would surprise anyone reading the command that produced the descriptor.
--context selects which cluster, for both.
draugr survey on its own lists the surveyors rather than guessing what you meant to discover.
Merging, not overwriting
A survey folds discovered components into the Saga already at --output instead of replacing
it, and that is the default rather than a flag. It is what makes discovery repeatable: the
classifications, exclusions and
per-component overrides you added by hand are preserved, and whatever has appeared in the
environment since the last run is added alongside them. Pass --replace when you do want to
start again.
Without it, survey writes a fresh descriptor. Right for the first run, and a way to lose
hand-written context on every one after that.
What k8s-images records beyond the image
Two things that matter later:
The running digest. A tag is mutable; the digest is the bytes actually running. Recording it makes caching content-addressed, a rebuilt image pushed under the same tag re-scans immediately instead of serving a stale result until its TTL expires, and it means the finding describes what is deployed rather than what the tag points at today. See content-hash caching.
A proposed exposure. When scoped to a specific namespace, k8s-images infers each
component's exposure from cluster topology: an Ingress or externally-reachable Service means
public, a NetworkPolicy that scopes it means restricted, and anything else is internal.
What discovery cannot do for you
A surveyor reads the environment, so it can only recover what the environment knows.
criticality is not in the cluster. What it costs your business when a component fails is not a
property of any manifest. It is a judgement, and Draugr will not manufacture one. Discovery leaves
it unset; draugr classify asks you.
Until both axes are set, prioritization has half its input.
The proposed exposure is a proposal, and the survey tells you which ones it made. Topology is
good evidence, not proof. An Ingress says a route exists, not who may take it, and a Service with
none may still be reachable through a gateway the cluster cannot see.
exposure proposed from cluster topology, not confirmed. Run `draugr classify` to set it:
payments public
cert-manager internal
Each is named with the value chosen, because the next action is per component. A component that already carries an exposure is left alone and not listed: the merge keeps a decision somebody made, so there is nothing there to confirm.
The failure discovery protects you from is a component nobody scanned. The one it cannot protect you from is a component ranked as though it does not matter.
Going deeper
draugr survey, every flagdraugr classify. Set the two risk axes- The Saga. What the fragments are merged into
- Prioritization, what
exposureandcriticalitydrive k8s-images·github-org-repos·gitlab-group-projects·azure-devops-repos, per-surveyor detail