Kubernetes Discovery
The Infracast Kubernetes plugin uses the Kubernetes API to enumerate cluster resources across all namespaces. It discovers workloads (deployments, pods, StatefulSets, DaemonSets), services, RBAC configuration, ConfigMaps, Secrets (metadata only), network policies, and persistent volumes. Authentication is via a kubeconfig file or in-cluster service account.
How It Works
- Infracast authenticates to the Kubernetes API server using the provided kubeconfig or service account token
- All namespaces are enumerated
- For each namespace, workloads, services, pods, and policy resources are discovered in parallel
- Cluster-scoped resources (cluster roles, persistent volumes, nodes) are enumerated separately
- All resources are linked via namespace containment and owner reference edges
Prerequisites
- HTTPS access from the Infracast collector to the Kubernetes API server (TCP/6443 or 443)
- A
ServiceAccountwith aClusterRolegranting read access to all relevant API groups - A kubeconfig file or the collector running inside the cluster
Creating the Discovery ServiceAccount
Apply this manifest to your cluster to create a read-only service account for Infracast:
apiVersion: v1
kind: ServiceAccount
metadata:
name: infracast-discovery
namespace: infracast
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: infracast-discovery
rules:
- apiGroups: [""]
resources:
- namespaces
- nodes
- pods
- services
- serviceaccounts
- configmaps
- secrets
- persistentvolumes
- persistentvolumeclaims
- endpoints
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources:
- deployments
- replicasets
- statefulsets
- daemonsets
verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["get", "list", "watch"]
- apiGroups: ["autoscaling"]
resources:
- horizontalpodautoscalers
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources:
- networkpolicies
- ingresses
verbs: ["get", "list", "watch"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources:
- clusterroles
- clusterrolebindings
- roles
- rolebindings
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: infracast-discovery
subjects:
- kind: ServiceAccount
name: infracast-discovery
namespace: infracast
roleRef:
kind: ClusterRole
name: infracast-discovery
apiGroup: rbac.authorization.k8s.io
# Apply the manifest
kubectl create namespace infracast
kubectl apply -f infracast-rbac.yaml
# Extract a kubeconfig for Infracast
kubectl -n infracast create token infracast-discovery --duration=8760h > /tmp/infracast-k8s-token
Use kubectl create token (Kubernetes 1.24+) to generate a time-bounded token rather than a long-lived secret. Rotate the token periodically by updating the Infracast credential.
Registering the Credential in Infracast
infracast creds add \
--plugin kubernetes \
--name "k8s-prod-cluster" \
--type kubeconfig \
--kubeconfig-file /run/secrets/infracast-kubeconfig
Configuring the Discovery Job
discovery:
jobs:
- name: k8s-prod
plugin: kubernetes
credential: k8s-prod-cluster
schedule: "*/30 * * * *" # every 30 minutes
config:
cluster_name: "prod-cluster" # used as a prefix in all node IDs
# Optional: limit to specific namespaces (default: all)
namespaces:
- "production"
- "staging"
# Discover secrets metadata (names only, never values)
discover_secrets: true
# Discover ConfigMaps (names and keys only, not values)
discover_configmaps: true
What Gets Discovered
| Resource Type | Description |
|---|---|
k8s.namespace | Namespace (name, labels, annotations, status phase) |
k8s.node | Cluster node (name, roles, kernel version, container runtime, allocatable CPU/memory, conditions) |
k8s.deployment | Deployment (name, namespace, replicas, selector, strategy, container images) |
k8s.pod | Pod (name, namespace, phase, node assignment, container names, restart count) |
k8s.service | Service (name, namespace, type, cluster IP, ports, selector, external IP/hostname) |
k8s.stateful_set | StatefulSet (name, namespace, replicas, service name, volume claims) |
k8s.daemon_set | DaemonSet (name, namespace, selector, container images, node selector) |
k8s.configmap | ConfigMap (name, namespace, key names — values not stored) |
k8s.secret | Secret (name, namespace, type — values never stored) |
k8s.cluster_role | ClusterRole (name, rules summary) |
k8s.cluster_role_binding | ClusterRoleBinding (name, subjects, roleRef) |
k8s.role | Namespaced Role (name, namespace, rules summary) |
k8s.role_binding | Namespaced RoleBinding (name, namespace, subjects, roleRef) |
k8s.service_account | ServiceAccount (name, namespace) |
k8s.network_policy | NetworkPolicy (name, namespace, pod selector, ingress/egress rules) |
k8s.persistent_volume | PersistentVolume (name, capacity, access modes, storage class, reclaim policy, status) |
k8s.persistent_volume_claim | PersistentVolumeClaim (name, namespace, bound PV, access modes, storage class, capacity request) |
k8s.job | Job (name, namespace, completions, parallelism, status, container images) |
k8s.cron_job | CronJob (name, namespace, schedule, last schedule time, concurrency policy) |
k8s.hpa | HorizontalPodAutoscaler (name, namespace, target ref, min/max replicas, current/desired replicas, metrics) |
Secret values are never collected or stored. Only metadata (name, namespace, type) is recorded. ConfigMap values are similarly omitted — only key names are captured.
Troubleshooting
Unauthorized or Forbidden API responses
Symptom: Error: Kubernetes API error: 401 Unauthorized or 403 Forbidden
Checks:
- Verify the token has not expired:
kubectl auth can-i list deployments --as=system:serviceaccount:infracast:infracast-discovery - Verify the ClusterRoleBinding is correctly applied:
kubectl get clusterrolebinding infracast-discovery - For external access, confirm the kubeconfig server URL and CA are correct
Pods discovered but deployments missing
Symptom: Pods show up but their parent deployments do not
Cause: The service account may be missing list access to the apps API group.
Fix: Re-apply the RBAC manifest above and confirm:
kubectl auth can-i list deployments \
--as=system:serviceaccount:infracast:infracast-discovery
Cluster has many namespaces, discovery is slow
Symptom: Discovery jobs take more than 10 minutes
Fix: Limit discovery to production namespaces and increase the job schedule interval:
config:
namespaces:
- "production"
- "kube-system"
API server unreachable from collector
Symptom: Error: dial tcp x.x.x.x:6443: i/o timeout
Checks:
- Verify network connectivity from the collector to the API server
- If using an internal load balancer, check the LB health checks
- For EKS/GKE/AKS, ensure the collector's IP is in the API server authorized network list