Skip to content
Documentation

Modules

Kubernetes (KSPM)

What Ctadel reads in your clusters, how it gets access for each distribution, the rule families, and the “Kubernetes Security” and “Kubernetes” pages.

The Kubernetes module connects to the API of each of your clusters, records workloads, permissions, network, images and nodes, then evaluates a catalogue of configuration rules on what it read. It installs nothing in the cluster. The images it records are then analysed by the Vulnerabilities module.

Which clusters are scanned

At each full inventory, Ctadel starts one scan per cluster present in the graph, with the credentials of the cloud account that owns it. A cluster connected by hand with a kubeconfig receives that kubeconfig, stored encrypted, instead of cloud credentials. A scan can also be started for a single cluster from "Settings", "Kubernetes Clusters" section, with the "Scan Now" or "Rescan" button.

DistributionHow Ctadel gets access
Amazon EKSIt reads the cluster's endpoint and certificate through the EKS API, then authenticates with a presigned STS token valid for 60 seconds, as aws eks get-token does. Before that, it tries to create an EKS access entry for its own IAM identity and to associate the AmazonEKSClusterAdminPolicy policy with it; this succeeds on clusters in API or API_AND_CONFIG_MAP authentication mode when the account is allowed to. Otherwise the cluster moves to "Needs Config" and the "Instructions" button shows the read-only ctadel-scanner role to create and the command that maps Ctadel's identity to that group (access entry, or the aws-auth ConfigMap on clusters in CONFIG_MAP mode).
Azure AKSIt calls listClusterAdminCredential with the service principal and uses the administrator kubeconfig returned.
Google GKEIt reads the cluster's endpoint through the GKE API and authenticates with an OAuth token of the service account.
Scaleway KapsuleIt downloads the cluster's kubeconfig through the Scaleway API.
OVHcloud MKSIt downloads the cluster's kubeconfig through the OVHcloud API.
OUTSCALE OKSIt downloads the cluster's kubeconfig through the region's OKS API, with the account's access key.
Provided kubeconfigYou paste a kubeconfig in "Connect Cluster" (or "Connect with kubeconfig" on a cluster already discovered). It is used as is, for any cluster, including outside a cloud.

A provided kubeconfig is checked when saved and each time it is loaded: exec plugins and auth-provider entries, file paths (tokenFile, client-certificate, client-key, certificate-authority), impersonation (as, as-groups) and proxies are refused; the API server must be an https address. The token or certificate must be inlined in the file. The API server must be reachable from your Ctadel instance.

Each cluster's state is shown in "Settings": "Connected", "Scanning...", "Needs Config" (permissions to grant, with the error details), "Error" or "Not Scanned".

What is read

Ctadel reads only through the Kubernetes API, with the get and list verbs. It records:

FamilyObjects and properties
NodesName, internal and external addresses, OS image, kubelet version, role (control plane or worker node, from labels and taints)
WorkloadsEvery pod, with its controller and replica count, its service account and the cloud identity annotated on that account, its containers and their security contexts
ImagesEach image referenced by a container, with the pods that use it
NamespacesName and Pod Security Admission level (pod-security.kubernetes.io/enforce)
RBACRoleBindings and ClusterRoleBindings, their subjects, and what the bound roles grant (wildcards, bind, escalate, impersonate, secrets, exec into pods)
ServicesType, external address (the load balancer's, a declared external IP, or a node's external address for a NodePort) and selected pods
Persistent volumesPersistentVolumeClaims and the cloud volume behind them, with the pod that mounts them

These objects are written to the graph: the Attack paths module uses them to link an exposed service, a privileged pod, a service account and a cloud identity. Volumes behind a PersistentVolumeClaim that are attached to no machine are then copied and read as disks by the Data, Secrets and Hosts modules.

The rules

Each rule carries a severity and is evaluated on the cluster's objects. The rules reference the CIS Kubernetes Benchmarks and the Pod Security Standards. One finding is raised per rule and resource; when a resource breaks the same rule several times (two privileged containers in a pod), the message lists them in a single finding.

FamilyWhat is checked
Pod specificationHost namespaces (network, PID, IPC), hostPath volumes and sensitive host paths, container runtime socket, automatic mounting of the service account token, default service account, seccomp profile
Security contextsPrivileged containers, running as root, runAsNonRoot, read-only root filesystem, privilege escalation, allowed seccomp profiles, fsGroup
CapabilitiesNET_RAW, NET_ADMIN, dropping all capabilities, added capabilities other than NET_BIND_SERVICE
WorkloadsReplica count, liveness and readiness probes, CPU and memory limits and requests, latest tag, image pull policy, anti-affinity
RBACBindings to system:anonymous, system:authenticated and system:masters, wildcards on verbs, resources and API groups, bind, escalate and impersonate rights, access to secrets, pods/exec, pod creation, proxying to nodes, service accounts bound to cluster-admin or edit at cluster scope
Secrets and ConfigMapsSecrets passed as environment variables, Opaque secrets in the default namespace, ConfigMap keys that look like credentials, expired TLS secrets
NamespacesWorkloads in default, kube-system or kube-public, missing ResourceQuota, LimitRange or Pod Security Admission label
NetworkNamespaces with no NetworkPolicy, no ingress or egress restriction, no default deny; Ingress without TLS, with a wildcard host or without protective annotations; public LoadBalancer Services open to every address, NodePort Services
CronJobsconcurrencyPolicy, history limits, privileged containers, activeDeadlineSeconds
Service accountsAutomatic token mounting, default account with mounted secrets, unused accounts, broad cluster-wide permissions

For ConfigMap keys, a name that announces a credential (password, secret, api_key, token) is only reported when its value can be a credential: a URL, a path, a boolean, a number, a template ($\{DB_PASSWORD\}) or a key that names a location (token_endpoint, secret_name, password_file) are not.

A rule whose check fails on the API (missing permission, API unavailable) is not evaluated: its existing findings are kept as they are. Findings of evaluated rules that no longer come up are closed. The "Policies" page, KSPM tab, lets you enable or disable each rule; see Policies. A few rules ship disabled by default; the reason is given in their description.

Container images

After the cluster is read, the unique images are analysed with Trivy, with at most four minutes per image. To pull private images, Ctadel uses the cluster's pull secrets (imagePullSecrets of type dockerconfigjson or dockercfg) and then, for the scanned cloud account's own registry when no pull secret covers it, the account's credentials: Amazon ECR, Azure Container Registry, Google Container Registry and Artifact Registry, the Scaleway registry. These credentials stay in the Kubernetes scanner, in a configuration specific to the scan.

Each image yields the list of its packages (system and application), its operating system and its digest, linked to the pods that use it; the matching against vulnerabilities is described in Vulnerabilities. The secrets Trivy finds in the image layers are sent to the Secrets module. An image that could not be pulled (private registry without credentials, access denied) is reported with the state pull_failed: it has no package and no vulnerability, which does not mean it is clean.

The pages

The "Kubernetes Security" page (address /kspm) lists the findings of the active project, open and closed, sorted by severity then by date, with the columns "Severity", "Status", "Rule", "Kind", "Resource" (name and namespace) and "Cluster". Filters cover "Severity", "Status", "Kind", "Cluster" and "Namespace"; grouping covers the same fields. The "Export CSV" button exports the filtered list. The page shows at most 2,000 findings. Clicking a row opens the detail panel, described in Reading a finding.

The "Kubernetes" page (address /kubernetes) presents the inventory in three tabs:

TabColumns
"Clusters""Name", "Cloud", "Region", "Version", "Nodes", "Workloads", "Issues", "Public", "CNI", "Status"
"Nodes""Name", "Cloud", "Cluster", "Role", "Age", "Internal IP", "Kubelet"
"Workloads""Name", "Cloud", "Namespace", "Kind", "Cluster", "Image", "Issues"

The "Issues" column counts the object's open KSPM findings. A node's "Age" column is the date Ctadel first saw it.

The Kubernetes page, Clusters tab, with the list of clusters, their nodes, workloads and issues.
Figure 1. Figure 1. The “Kubernetes” page, “Clusters” tab, on the demo instance.

Runtime detection

The module also carries detection checks on a cluster's current state (recent privileged pods, ephemeral containers, RBAC bindings created within the observation window, recently exposed services, images outside trusted registries, drift between the declared digest and the running one). These detections feed the "Runtime" page, which is in internal validation and not available to customers.

Limits

  • The module reads the Kubernetes API and nothing else: it sees neither running processes, nor network traffic, nor the kubelet and operating system configuration of the nodes. Node hardening is covered by the Hosts module from a copy of their disk.
  • On EKS, the automatic path requests the AmazonEKSClusterAdminPolicy policy for Ctadel's identity; the read-only ctadel-scanner role is applied only when you follow the "Instructions" by hand, on a cluster where the automatic creation failed. On AKS, Ctadel uses the cluster's administrator kubeconfig. In both cases the access obtained exceeds the get and list verbs used.
  • Clusters whose API server is reachable only from a private network cannot be scanned.
  • A rule whose check fails on the API keeps its previous findings without updating them.
  • Node readiness, CPU and memory are not collected; the "Nodes" page does not show a NotReady node.
  • Images that could not be pulled have no package recorded. The analysis of an image stops after four minutes.
  • The availability rules (replicas, probes, anti-affinity, resource limits) describe robustness, not exposure; their severity is low or medium.
  • Runtime detections are not available to customers. exec and port-forward events cannot be detected without the API server's audit log, which the module does not read.
  • Disabled rules stay in the catalogue and produce nothing.