KubeHound DSL
The KubeHound graph ships with a custom DSL that simplifies queries for the most common use cases
Using the KubeHound graph
The KubeHound DSL can be used by starting a traversal with kh
instead of the traditional g
. All gremlin queries will work exactly as normal, but a number of additional methods, specific to KubeHound, will be available.
List of available methods
DSL definition code available here.
Retrieve cluster data
These methods are defined in the
KubeHoundTraversalSourceDsl
class.
Method | Gremlin equivalent | Example usage |
---|---|---|
.cluster([string...]) |
.has("class","Cluster") |
kh.cluster("kind-kubehound.local") |
.containers([string...]) |
.has("class","Container") |
kh.cluster("kind-kubehound.local").containers("nginx") |
.endpoints([int]) |
.has("class","Endpoint") |
kh.cluster("kind-kubehound.local").endpoints(3) |
.hostMounts([string...]) |
.has("class","Volume").has("type", "HostPath") |
kh.cluster("kind-kubehound.local").hostMounts("/proc") |
.nodes([string...]) |
.has("class","Node") |
kh.cluster("kind-kubehound.local").nodes("control-plane") |
.permissions([string...]) |
.has("class","PermissionSet") |
kh.cluster("kind-kubehound.local").permissions("system::kube-controller") |
.pods([string...]) |
.has("class","Pod") |
kh.cluster("kind-kubehound.local").pods("app-pod") |
.run([string...]) |
.has("runID", P.within(ids)) |
kh.run("01he5ebh73tah762qgdd5k4wqp") |
.services([string...]) |
.has("class","Endpoint").has("exposure", "EXTERNAL") |
kh.cluster("kind-kubehound.local").services("app-front-proxy") |
.sas([string...]) |
.has("class","Identity").has("type", "ServiceAccount") |
kh.cluster("kind-kubehound.local").sas("postgres-admin") |
.users([string...]) |
.has("class","Identity").has("type", "User") |
kh.cluster("kind-kubehound.local").users("user@domain.tld") |
.groups([string...]) |
.has("class","Identity").has("type", "Group") |
kh.cluster("kind-kubehound.local").groups("engineering") |
.volumes([string...]) |
.has("class","Volume") |
kh.cluster("kind-kubehound.local").volumes("db-data") |
Retrieving attack oriented data
These methods are defined in the
KubeHoundTraversalDsl
class.
Method | Gremlin equivalent |
---|---|
.attacks() |
.outE().inV().path() |
.critical() |
.has("critical", true) |
.criticalPaths(int) |
see KubeHoundTraversalDsl.java |
.criticalPathsFilter(int, string...) |
see KubeHoundTraversalDsl.java |
.criticalPathsFreq([maxHops]) |
see KubeHoundTraversalDsl.java |
.hasCriticalPath() |
.where(__.criticalPaths().limit(1)) |
.minHopsToCritical([maxHops]) |
see KubeHoundTraversalDsl.java |
For more detailed explanation, please see below.
Example of a kubehound DSL capabilities:
// Example returning all attacks from containers running the cilium 1.11.18 image
kh.containers().has("image", "eu.gcr.io/internal/cilium:1.11.18").attacks()
KubeHound Constants
Endpoint Exposure
Represents the exposure level of endpoints in the KubeHound graph
// Defines the exposure of an endpoint within the KubeHound model
public enum EndpointExposure {
None,
ClusterIP, // Container port exposed to cluster
NodeIP, // Kubernetes endpoint exposed outside the cluster
External, // Kubernetes endpoint exposed outside the cluster
}
Traversal Source Reference
Run Step
Starts a traversal that finds all vertices from the specified KubeHound run(s).
Example usage:
// All vertices in the graph from a single run
kh.run("01he5ebh73tah762qgdd5k4wqp")
// All vertices in the graph from a multiple runs
kh.run("01he5ebh73tah762qgdd5k4wqp", "01he5eagzbnhtfnwzg7xxbyfz4")
// All containers in the graph from a single run
kh.run("01he5ebh73tah762qgdd5k4wqp").containers()
Cluster Step
Starts a traversal that finds all vertices from the specified cluster(s).
Example usage:
// All vertices in the graph from the kind-kubehound.local cluster
kh.cluster("kind-kubehound.local")
// All containers in the graph from the kind-kubehound.local cluster
kh.cluster("kind-kubehound.local").containers()
Containers Step
Starts a traversal that finds all vertices with a "Container" label and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All containers in the graph
kh.containers()
// All containers in the graph with name filter
kh.containers("elasticsearch", "mongo")
// All containers in the graph with additional filters
kh.containers().has("namespace", "ns1").limit(10)
Pods Step
Starts a traversal that finds all vertices with a "Pod" label and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All pods in the graph
kh.pods()
// All pod in the graph with name filter
kh.pods("app-pod", "sidecar-pod")
// All pods in the graph with additional filters
kh.pods().has("namespace", "ns1").limit(10)
Nodes Step
Starts a traversal that finds all vertices with a "Node" label and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All nodes in the graph
kh.nodes()
// All nodes in the graph with name filter
kh.nodes("control-plane")
// All nodes in the graph with additional filters
kh.nodes().has("team", "sre").limit(10)
Escapes Step
Starts a traversal that finds all container escape edges from a Container vertex to a Node vertex and optionally allows filtering of those vertices on the "nodeNames" property.
Example usage:
// All container escapes in the graph
kh.escapes()
// All container escapes in the graph with node name filter
kh.escapes("control-plane")
Endpoints Step
Starts a traversal that finds all vertices with a "Endpoint" label.
GraphTraversal<Vertex, Vertex> endpoints()
GraphTraversal<Vertex, Vertex> endpoints(EndpointExposure exposure)
Example usage:
// All endpoints in the graph
kh.endpoints()
// All endpoints in the graph with additional filters
kh.endpoints().has("port", 3000).limit(10)
// All endpoints with K8s service exposure
kh.endpoints(EndpointExposure.External)
Services Step
Starts a traversal that finds all vertices with a "Endpoint" label representing K8s services.
Example usage:
// All services in the graph
kh.services()
// All services in the graph with name filter
kh.services("jmx", "redis")
// All services in the graph with additional filters
kh.services().has("port", 9999).limit(10)
Volumes Step
Starts a traversal that finds all vertices with a "Volume" label and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All volumes in the graph
kh.volumes()
// All volumes in the graph with name filter
kh.volumes("db-data", "proc-mount")
// All volumes in the graph with additional filters
kh.volumes().has("sourcePath", "/").has("app", "web-app")
HostMounts Step
Starts a traversal that finds all vertices representing volume host mounts and optionally allows filtering of those vertices on the "sourcePath" property.
Example usage:
// All host mounted volumes in the graph
kh.hostMounts()
// All host mount volumes in the graph with source path filter
kh.hostMounts("/", "/proc")
// All host mount volumes in the graph with additional filters
kh.hostMounts().has("app", "web-app").limit(10)
Identities Step
Starts a traversal that finds all vertices with a "Identity" label and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All identities in the graph
kh.identities()
// All identities in the graph with name filter
kh.identities("postgres-admin", "db-reader")
// All identities in the graph with additional filters
kh.identities().has("app", "web-app").limit(10)
SAS Step
Starts a traversal that finds all vertices representing service accounts and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All service accounts in the graph
kh.sas()
// All service accounts in the graph with name filter
kh.sas("postgres-admin", "db-reader")
// All service accounts in the graph with additional filters
kh.sas().has("app", "web-app").limit(10)
Users Step
Starts a traversal that finds all vertices representing users and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All users in the graph
kh.users()
// All users in the graph with name filter
kh.users("postgres-admin", "db-reader")
// All users in the graph with additional filters
kh.users().has("app", "web-app").limit(10)
Groups Step
Starts a traversal that finds all vertices representing groups and optionally allows filtering of those vertices on the "name" property.
Example usage:
// All groups in the graph
kh.groups()
// All groups in the graph with name filter
kh.groups("postgres-admin", "db-reader")
// All groups in the graph with additional filters
kh.groups().has("app", "web-app").limit(10)
Permissions Step
Starts a traversal that finds all vertices with a "PermissionSet" label and optionally allows filtering of those vertices on the "role" property.
Example usage:
// All permissions sets in the graph
kh.permissions()
// All permissions sets in the graph with role filter
kh.permissions("postgres-admin", "db-reader")
// All permissions sets in the graph with additional filters
kh.permissions().has("app", "web-app").limit(10)
Traversal Reference
Attacks Step
From a Vertex traverse immediate edges to display the next set of possible attacks and targets
Example usage:
// All attacks possible from a specific container in the graph
kh.containers("pwned-container").attacks()
Critical Step
From a Vertex filter on whether incoming vertices are critical assets
Example usage:
// All critical assets in the graph
kh.V().critical()
// Check whether a specific permission set is marked as critical
kh.permissions("system::kube-controller").critical()
CriticalPaths Step
From a Vertex traverse edges until {@code maxHops} is exceeded or a critical asset is reached and return all paths.
Example usage:
// All attack paths from services to a critical asset
kh.services().criticalPaths()
// All attack paths (up to 5 hops) from a compromised credential to a critical asset
kh.group("engineering").criticalPaths(5)
CriticalPathsFilter Step
From a Vertex traverse edges EXCLUDING labels provided in exclusions
until maxHops
is exceeded or a critical asset is reached and return all paths.
Example usage:
// All attack paths (up to 10 hops) from services to a critical asset excluding the TOKEN_BRUTEFORCE and TOKEN_LIST attacks
kh.services().criticalPathsFilter(10, "TOKEN_BRUTEFORCE", "TOKEN_LIST")
HasCriticalPath Step
From a Vertex filter on whether incoming vertices have at least one path to a critical asset
Example usage:
MinHopsToCritical Step
From a Vertex returns the hop count of the shortest path to a critical asset.
<E2 extends Comparable> GraphTraversal<S, E2> minHopsToCritical()
<E2 extends Comparable> GraphTraversal<S, E2> minHopsToCritical(int maxHops)
Example usage:
// Shortest hops from a service to a critical asset
kh.services().minHopsToCritical()
// Shortest hops from a compromised engineer credential to a critical asset (up to 6)
kh.group("engineering").minHopsToCritical(6)
CriticalPathsFreq Step
From a Vertex returns a group count (by label) of paths to a critical asset.
<K> GraphTraversal<S, Map<K, Long>> criticalPathsFreq()
<K> GraphTraversal<S, Map<K, Long>> criticalPathsFreq(int maxHops)
Example usage:
// Most common critical paths from services
kh.services().criticalPathsFreq()
// Most common critical paths from a compromised engineer credential of up to 4 hops
kh.group("engineering").criticalPathsFreq(4)
Sample output:
{
"path[Endpoint, ENDPOINT_EXPLOIT, Container, IDENTITY_ASSUME, Identity, PERMISSION_DISCOVER, PermissionSet]": 6,
"path[Endpoint, ENDPOINT_EXPLOIT, Container, VOLUME_DISCOVER, Volume, TOKEN_STEAL, Identity, PERMISSION_DISCOVER, PermissionSet]": 6,
"path[Endpoint, ENDPOINT_EXPLOIT, Container, CE_NSENTER, Node, IDENTITY_ASSUME, Identity, PERMISSION_DISCOVER, PermissionSet]": 1,
"path[Endpoint, ENDPOINT_EXPLOIT, Container, CE_MODULE_LOAD, Node, IDENTITY_ASSUME, Identity, PERMISSION_DISCOVER, PermissionSet]": 1,
"path[Endpoint, ENDPOINT_EXPLOIT, Container, CE_PRIV_MOUNT, Node, IDENTITY_ASSUME, Identity, PERMISSION_DISCOVER, PermissionSet]": 1
}