Inspecting and Exploring the API
You've inherited a cluster with no documentation. You need to understand what custom resources exist, what API endpoints are exposed, and what permissions are configured, all from kubectl.
The first 30 minutes after gaining access to an unfamiliar cluster determine whether you can secure it or whether you will fly blind for weeks. The good news: the cluster itself documents what it has. Every resource type, every custom CRD, every available API endpoint is queryable from kubectl with a small set of commands.
This lesson is the cluster reconnaissance toolkit, useful equally for security auditors, attackers, and engineers inheriting an unfamiliar cluster. Knowing how to enumerate the cluster fast is the foundation of every security investigation.
Attack path / threat explanation
Cluster reconnaissance from inside a pod (or from any kubectl context) maps the attack surface. The standard attacker (or auditor) workflow:
- Establish identity.
kubectl auth whoamiconfirms which user/SA the credentials authenticate as. - Enumerate permissions.
kubectl auth can-i --listshows what the current identity can do. Often surprises: the default ServiceAccount may have access to more than expected. - Inventory resources.
kubectl api-resourceslists every resource type, including custom resources installed by operators. Custom resources often expose interesting attack surface (e.g., a Vault Agent CRD that grants secret access via custom config). - Look for sensitive resources. Secrets, ConfigMaps with credentials, ServiceAccounts with broad RBAC, RoleBindings that grant powerful access.
- Watch the verbose API trace.
kubectl -v=8shows the full request and response. Useful for understanding what the API returns and finding undocumented fields.
A defender uses the same workflow proactively. Knowing what is in the cluster is the only way to know what to protect.
The Kubernetes API is self-describing. Every resource type, every field, every API version is queryable through kubectl. An auditor who walks into an unfamiliar cluster can map its full attack surface in 15-30 minutes using only built-in commands. The same toolkit works for attackers; the difference is whether the auditor gets there first.
How it works under the hood
The API discovery flow:
API discovery: from kubectl to the OpenAPI schema
Click each step to explore
The mental model: every API resource has a (group, version, kind) identity, lives at a predictable URL pattern, and has a schema you can query. A few examples:
| Resource | Path |
|---|---|
| Pods (core, v1) | /api/v1/namespaces/{ns}/pods |
| Deployments (apps, v1) | /apis/apps/v1/namespaces/{ns}/deployments |
| Roles (rbac.authorization.k8s.io, v1) | /apis/rbac.authorization.k8s.io/v1/namespaces/{ns}/roles |
| Nodes (core, v1, cluster-scoped) | /api/v1/nodes |
Cluster-scoped resources (Nodes, ClusterRoles, PersistentVolumes, CRDs) live at paths without the namespaces/{ns} segment. Namespace-scoped resources include it.
The verbose mode levels of kubectl, in order of usefulness:
-v=6: shows the URLs being requested. Good for "what is kubectl actually doing?"-v=7: adds request and response headers. Useful for auth debugging.-v=8: adds full request and response bodies. The most useful level for understanding behavior.-v=9: adds the equivalent curl command, ready to copy-paste.
Once you know how to read these levels, kubectl becomes a debugging tool for the API itself, not just for managing resources.
Defense architecture
Cluster recon is also defense recon. The auditor uses the same tools to know what to protect:
1. Inventory CRDs and operators. Custom resources are where operators (Vault, Cert-Manager, Prometheus, ArgoCD, plus dozens of others) extend the API. Each operator is a piece of code running with cluster permissions; each custom resource is an attack surface. kubectl get crds lists every CRD installed.
2. Map RBAC reachability. For each ServiceAccount that pods use, run kubectl auth can-i --list --as=system:serviceaccount:NS:NAME to see what the SA can do. Surprises here are usually privilege escalation risks.
3. Find anonymous-accessible endpoints. kubectl --as=system:anonymous get --raw /api/v1 returns 200 if anonymous auth grants access. This should always be 401 or 403; if it is 200, you have anonymous auth enabled and need to disable it.
4. Audit the OpenAPI spec for unfamiliar resources. A cluster you are auditing may have CRDs you have never heard of. Each one is a potential attack vector.
5. Use kubectl get --raw for low-level investigation. When standard kubectl commands abstract away too much detail, --raw gives you direct API access:
kubectl get --raw /api/v1/namespaces/default/secrets/my-secret
Returns the raw JSON response from the API server, including system fields normally hidden by kubectl.
Configuration examples
The first 5 minutes of any cluster audit:
# 1. Who am I?
kubectl auth whoami
# 2. What can I do?
kubectl auth can-i --list
# 3. What API groups exist?
kubectl api-versions
# 4. What resources exist (including custom ones)?
kubectl api-resources -o wide
# 5. Are there any custom resources installed?
kubectl get crds -o custom-columns=NAME:.metadata.name,GROUP:.spec.group,KIND:.spec.names.kind
# 6. List ServiceAccounts and their RoleBindings (cluster-wide audit)
kubectl get serviceaccounts -A
kubectl get clusterrolebindings -o json | jq '.items[] | {
name: .metadata.name,
role: .roleRef.name,
subjects: [.subjects[]? | "\(.kind)/\(.namespace // "<cluster>")/\(.name)"]
}'
# 7. Find any ServiceAccount with cluster-admin
kubectl get clusterrolebindings -o json | jq '.items[] |
select(.roleRef.name == "cluster-admin") |
{name: .metadata.name, subjects: .subjects}'
For deeper investigation of a specific endpoint:
# Direct API call with current credentials
kubectl get --raw /api/v1/namespaces/kube-system/secrets
# With verbose mode to see the full HTTP exchange
kubectl -v=9 get pods 2>&1 | grep -E '^I.*curl' | head -3
For reverse-engineering an undocumented operator:
# What CRDs does the operator install?
kubectl get crds -l app.kubernetes.io/managed-by=my-operator
# Schema of a CRD
kubectl explain mycustomresource.spec --recursive
# What the operator's ServiceAccount can do
kubectl auth can-i --list \
--as=system:serviceaccount:my-operator-namespace:my-operator-sa
Common misconfigurations
- Anonymous user with discovery access. Should be denied. Test:
kubectl --as=system:anonymous get --raw /api. - Default ServiceAccount with broad RBAC. Common when admins mis-bind a ClusterRole. Test:
kubectl auth can-i --list --as=system:serviceaccount:default:default. - CRDs installed but never audited. Operators bring their own RBAC and resources; auditing only built-in resources misses half the picture.
- OpenAPI spec exposed unauthenticated. The schema itself is rarely sensitive but combined with version info gives attackers a roadmap.
kubectl auth can-i --listreturning more than expected for service accounts. Frequent privilege escalation source.- Verbose mode credentials leaked in logs.
kubectl -v=8includes the Authorization header in its output. Never paste that output into a chat or ticket. - No regular cluster inventory. Without periodic enumeration, you do not know what changed; new operators or CRDs add attack surface invisibly.
How would you audit a cluster you've never seen before to understand its full API surface and any custom resources?