Ctadel

KSPM: Kubernetes Security Posture Management

Why KSPM is its own thing

The cloud APIs that power CSPM only see what the cloud provider exposes about your cluster, control-plane logging, public/private endpoints, node group sizes. They cannot see:

  • Whether a Deployment runs as privileged: true.
  • Whether the default ServiceAccount is bound to cluster-admin.
  • Whether NetworkPolicy is enforced.
  • Whether kubelet runs with --anonymous-auth=true.

These all require talking to the Kubernetes API server directly. That's KSPM.

What KSPM looks for

The rule set at launch fall into a few buckets:

CategoryExamples
Pod SecurityPrivileged containers, runAsRoot, host network, host PID, missing seccomp
RBACWildcard verbs, cluster-admin on a default SA, unused roles
NetworkNo NetworkPolicy namespace coverage, exposed dashboards
Resource limitsMissing CPU/memory limits, missing requests
Image hygieneImages pulled by :latest, no image signing
API serverAnonymous auth, audit logging disabled
Admission controlsMissing PSA / OPA / Kyverno enforcement

Rules align with the CIS Kubernetes benchmark plus the Pod Security Standards (Baseline and Restricted).

How Ctadel scans Kubernetes

You connect a cluster by giving Ctadel a read-only kubeconfig or a service account token. We use list and get on every namespace, plus a few cluster-scoped resources.

  • Cadence: daily. Cluster state is cheap to read.
  • Coverage: every namespace by default. You can exclude system namespaces if you want.
  • Connection types: cloud-managed (EKS, AKS, GKE, Scaleway Kapsule) or self-hosted (kubeadm, k3s).

For cloud-managed clusters, Ctadel correlates the cluster node in the security graph back to its cloud control-plane representation. That's how toxic combinations like "public EKS API + cluster-admin role on a default SA + node IAM role with S3 write" are detected.

What ends up in a KSPM finding

FieldWhat it is
Rule keye.g. K8S-PRIVILEGED
Cluster IDStable identifier of the cluster
NamespaceKubernetes namespace
KindDeployment, StatefulSet, Pod, etc.
Resource nameWorkload name
Severity, status, frameworksAs with all findings

What's next