Skip to content

Kubernetes Pentest

The NodeZero Kubernetes Pentest runs from inside your Kubernetes cluster to test the security of your cluster by identifying security misconfigurations and weaknesses that exist in your cluster.

Why should I run a NodeZero Kubernetes Pentest?
How to Run a Kubernetes Pentest


Why Should I Run a NodeZero Kubernetes Pentest?

NodeZero runs from inside your cluster to help simulate the scenario that an attacker has gained a foothold on your cluster.

The foothold could be because an attacker found a user's kubeconfig file in a git repository or maybe an attacker compromised a web application running inside a pod in your cluster.

By running the Kubernetes pentest from inside your cluster and fixing the identified weaknesses, your organization can reduce the risk of the risk and impact of these attacks against your Kubernetes cluster.


How to Run a Kubernetes Pentest

To conduct a Kubernetes Pentest against your cluster, you must first install the NodeZero Operator. The NodeZero Operator will be the launch point for all the Kubernetes Pentests you run against your cluster. You only need to install the operator once per cluster allowing you to continuously test the security of your Kubernetes clusters.

Once installed, the operator can be used to install a Runner or a single pentest.


Install the NodeZero Operator

Installation Requirements:

The NodeZero Operator and Kubernetes Pentest is supported on Kubernetes Cluster versions 1.24.0 and above.

You will need to have a terminal with kubectl and helm installed. Make sure kubectl is configured to use the context of your Kubernetes cluster.

The NodeZero Operator will need access to the following domains over port 443/TCP (Horizon3's NodeZero Gateway):

  • gateway.horizon3ai.com
  • api.gateway.horizon3ai.com
  • registry.gateway.horizon3ai.com
  • interact.gateway.horizon3ai.com
  • gateway.horizon3ai.eu
  • api.gateway.horizon3ai.eu
  • registry.gateway.horizon3ai.eu
  • interact.gateway.horizon3ai.eu
  • gateway.horizon3ai.au
  • api.gateway.horizon3ai.au
  • interact-cf.gateway.horizon3ai.au

Does the NodeZero Gateway feature support the NodeZero Operator?

Yes, the NodeZero Gateway supports the NodeZero Operator and NodeZero Kubernetes Pentests.

From the Pentest drop-down, select Kubernetes Operators.

Pentests drop-down line at the top level navigation - Kubernetes Operators link

Create Operator

Click the + Create Operator button.

Kubernetes Operators page - the Create Operator Button is at the top right of the table.

Input a descriptive name and click Submit.

Create Operator page - Operator Name field

Install Operator

Follow the installation directions by copying the helm upgrade command and pasting into a terminal with Helm and Kubectl.

What permissions are needed to install the NodeZero Operator?

An example ClusterRole CRD with the needed permissions can be found here.

Create Operator pop-up - copy helm upgrade button


Install a Kubernetes Runner

From the Pentest drop-down, select Runners.

Pentests drop-down menu at the top level navigation of the UI has the Runners link.

Create Runner

Click the Install Runner button.

Runners page - Install Runner button at the top right of the table.

Specify a name for the Runner, select the Use Kubernetes Runner toggle, specify a namespace, and then click Submit.

Runner per namespace

A Kubernetes Runner lives inside a namespace, meaning that any pentests that use that Runner will run from that namespace. If desired, you can install a Runner in each namespace.

Install Runner pop-up page - Runner Name field, Use Kubernetes Switch, and Kubernetes Namespace field.

Install Runner

Copy this command and paste it into a terminal with Kubectl. Ensure that your current Kubectl context is set to your desired cluster. This one-time command will install the Runner using the NodeZero Runner Kubernetes Custom Resource Definition.

What permissions are needed to install the NodeZero Runner?

An example ClusterRole CRD with the needed permissions can be found here.

Install Runner pop-up page - Copy NodeZero Runner Kubernetes Resource button.


Control What NodeZero Can See

Before configuring the test itself, consider how Kubernetes role-based access control (RBAC) constrains what the test can access.

A Kubernetes Pentest is an assumed-breach test. NodeZero acts as an attacker who has already landed inside your cluster, and it starts from the identity you assign it: a Kubernetes namespace and service account.

That service account's permissions (its RBAC) determine how much of the cluster NodeZero can discover and attack. Setting these correctly is the single most important factor in the value you get from the test.

Test Scope Versus Results

When a pentest runs, NodeZero authenticates to the Kubernetes API server using the token from the service account you assign in the pentest configuration. Every enumeration and attack step (listing pods, reading secrets, mapping RBAC, and so on) uses that identity.

This means that the service account's permissions are a hard ceiling on the test:

  • If the service account can list pods, namespaces, and other resources across the cluster, NodeZero will enumerate the cluster and pursue attack paths from there.

  • If the service account has little or no access to K8s resources, NodeZero can authenticate, but its API calls will return "Forbidden." In this case, the test will be able to see only the pod it started in, and results will look empty or nearly empty.

This divide is by design. It faithfully simulates what a real attacker – who compromised a workload, running as that service account – could do. It also means that a limited result is usually a permissions signal, not a product limitation.

Permissions Versus Scope

The Operator and Runner ClusterRoles referenced elsewhere in this topic grant the permissions that NodeZero's own infrastructure needs to install and manage tests. They do not control how much of your cluster a pentest can see. Test scope is governed only by the service account you assign to the pentest.

Choosing a Privilege Level

Because the service account that you assign is the attacker's starting identity, choosing its permission level is really choosing which attack scenario you want to test. Below are options that match three scenarios:

Service Account Attack Scenario It Models Enumeration Reach
An existing application service account "What could an attacker do if they compromised this specific workload?" Whatever that workload is actually granted. Most realistic.
A new account bound to the built-in view ClusterRole A read-only foothold with broad visibility Reads most resources cluster-wide, but not secrets or RBAC objects (the built-in view role excludes these)
A new account bound to cluster-admin Worst-case, maximum blast radius Full read and write across the entire cluster

Guidance:

  • To demonstrate realistic risk, use an existing application service account that represents a plausible point of compromise.

  • To show broad discovery quickly, use the built-in view role. Be aware it does not include secrets or RBAC, so the secret-extraction and privilege-escalation findings will not run.

  • To exercise the full test, including secret extraction and RBAC privilege-escalation paths, use cluster-admin or the least-privilege custom role outlined below.

Grant the Service Account Permissions

The built-in view and cluster-admin roles already exist in every cluster, so with either of these, you only create a binding (skip to step 2 below). However, if you choose to use a dedicated service account, first create it (in step 1 or 3 below).

1. Create a dedicated service account (optional).

kubectl create serviceaccount nodezero-pentest -n <namespace>

(You can skip this and use an existing service account.)

2. Bind the service account to a role.

For broad, read-only discovery with the built-in view role:

kubectl create clusterrolebinding nodezero-pentest-view \
  --clusterrole=view \
  --serviceaccount=<namespace>:nodezero-pentest

For the full test (all findings, including secrets and privilege escalation) with the cluster-admin role:

kubectl create clusterrolebinding nodezero-pentest-admin \
  --clusterrole=cluster-admin \
  --serviceaccount=<namespace>:nodezero-pentest

ClusterRoleBinding, not RoleBinding

Use a ClusterRoleBinding, not a namespace-scoped RoleBinding. Cluster-wide enumeration requires cluster-scoped permissions. A RoleBinding would limit the test to a single namespace.

3. Least-privilege alternative: create a custom ClusterRole.

If your security policy does not allow granting view or cluster-admin, this custom role grants the minimum needed for a full-featured test. The first three rules let NodeZero see beyond its starting pod. The last two enable secret extraction and RBAC-based privilege-escalation findings.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nodezero-pentest-enum
rules:
# Core enumeration: required to see beyond the starting pod
- apiGroups: [""]
  resources: ["pods", "namespaces", "services", "serviceaccounts"]
  verbs: ["get", "list"]
- apiGroups: ["batch"]
  resources: ["jobs", "cronjobs"]
  verbs: ["get", "list"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "daemonsets", "statefulsets"]
  verbs: ["get", "list"]
# Deeper coverage: secret extraction and RBAC privilege-escalation findings
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  verbs: ["get", "list"]

Apply it and bind your service account:

kubectl apply -f nodezero-pentest-enum.yaml

kubectl create clusterrolebinding nodezero-pentest-enum \
  --clusterrole=nodezero-pentest-enum \
  --serviceaccount=<namespace>:nodezero-pentest

4. Confirm network reachability.

Enumerating resources through the API is separate from reaching them over the network. If a NetworkPolicy blocks pod-to-pod traffic from NodeZero's pod, some lateral-movement steps will not complete even when RBAC is correct. Confirm that no NetworkPolicy prevents NodeZero from reaching other pods in scope.

5. Assign the service account in the pentest.

When you reach the Kubernetes Settings step of the pentest configuration, enter the namespace and service account that you've prepared here.

Clean Up

After the test, remove anything you created for it.

# Remove the binding you used (match the name from step 2 or 3)
kubectl delete clusterrolebinding nodezero-pentest-view

# If you created the custom role
kubectl delete clusterrole nodezero-pentest-enum

# If you created a dedicated service account
kubectl delete serviceaccount nodezero-pentest -n <namespace>

Troubleshooting RBAC and Scope

This section covers how to resolve issues around the preceding configurations.

The Test Found Only the Starting Pod

This almost always means the assigned service account lacks cluster-wide read permissions, so the Kubernetes API returned "Forbidden" and NodeZero could only see its own pod. Bind the service account to a role with cluster-wide read (see "Grant the service account permissions" above) and rerun the test.


Run a Kubernetes Pentest

You can deploy NodeZero directly into any Kubernetes cluster, whether managed or self-managed, to pentest its security controls and vulnerabilities. Follow these steps to run a Kubernetes pentest within your network.

Once you've installed a NodeZero Operator in your cluster,you're ready to start a Kubernetes pentest. Open the NodeZero Portal's Pentests menu and select Pentests.

The Pentests link is at the top-level navigation of the UI

Click Run Assessment

Next, click Run Assessment. From the resulting tiles, select Infrastructure > Kubernetes Pentest.

The Run Assessment button is next to the Create Schedule button

Configure the Kubernetes Pentest

Name the Kubernetes Pentest

Name the Kubernetes Pentest and select a pentest template. For best results, etermine and follow a naming convention that will allow you to quickly find a pentest from your pentest list.

An example format: [date]|[library]|[NodeZero Src]|[scope]

This format might give you a name like: 2021-09-01|NodeZero|East-Coast-Bizops-Cluster|Full – which indicates that the NodeZero host was placed in the East Coast Bizops cluster, and the cluster CIDR ranges were explicitly added to scope.

Name section - Pentest Template and Name input fields are required.

Select the Kubernetes Scope

Since the goal of the Kubernetes Pentest is to test your cluster, all Kubernetes resources are treated as in scope, including nodes, pods, and services. This means you cannot exclude any Kubernetes resources from testing.

The Kubernetes pentest scope is a set of IPs and/or subnets (in CIDR notation) that you explicitly want NodeZero to test.

Depending on where your NodeZero host is deployed, reachability to the provided scope can be affected by how much privilege, access, and authentication NodeZero can capture or is given.

Unlike vulnerability tools that scan for device fingerprints and services, NodeZero enumerates devices in scope and then chains together context, exploitable vulnerabilities, misconfiguration, insecure or weak controls, and any data or loot that it captures, to identify attack paths by priority of impact while providing proof. Typically, the larger the scope, the more findings you'll see, as NodeZero has much more to chain together.

There are three options for the Include section (defined below):

  • Intelligent Scope
  • Full RFC 1918 (192.168.0.0/16, 172.16.10.0/24, 10.0.0.0/8)
  • Custom IP(s) or Subnet(s)
    • Auto-expand (Optional)

While Intelligent Scope and RFC 1918 can be used, we recommend using a Custom scope with auto-expand to specify the IP or subnet (CIDR) range of your Kubernetes Cluster to distinguish in-cluster assets. Without specifying this NodeZero has a hard time determining what is inside or outside your cluster and therefore what is in scope and should be tested. To improve visibility into Kubernetes resources like pods and services, consider pairing your scope with a Kubernetes Service Account that has the appropriate permissions.

We also recommend providing the CIDR ranges of the internal network or VPC that your cluster resides in to see if NodeZero can reach outside the cluster to your other hosts.

Scope section - it's required to enter IP range when Intelligent scope is turned off.

Attack Configuration

Select the types of services and vulnerabilities NodeZero will attempt to enumerate and exploit. For more information on choosing attack configuration options, visit the attack configuration options page.

Attack configuration section - checkboxes and expandable sections

Runner

If you would like to deploy the pentest using a Runner, feel free to select one! Please note that Kubernetes pentests can only use Kubernetes Runners.

Runner section - Kubernetes Runner, Namespace, and Service Account input fields.

Kubernetes Settings

You can specify a Kubernetes Namespace and a Kubernetes Service Account that you want NodeZero to use.

These are powerful settings that enable you to simulate the scenario where an attacker compromises a pod in your cluster. To simulate this scenario, simply set these two fields to match the configuration of one of your pods. We recommend simulating pods that have ports accessible from outside the cluster, as these are among an attacker's likely entry points into your cluster.

The namespace and service account that you select here define the identity NodeZero uses for the entire test. The service account's permissions determine how much of your cluster the test can reach. Before running the test, make sure the service account is scoped for the results you want – review Control What NodeZero Can See.

Runner per namespace

Since a Kubernetes Runner lives inside a namespace, when you select a Runner, the pentest must run from that namespace, and you will not be able to customize that field.

Review the Kubernetes Pentest Configuration

Once satisfied with your pentest selections, check the box to indicate you've reviewed all advanced configuration settings. Then click Run Pentest, which launches the Kubernetes pentest.

I have reviewed... required checkbox and Run Pentest button

Deploy NodeZero

While the pentest is provisioning, its companion one-time-use software module, NodeZero, is made ready for deployment on your NodeZero Host.

Preparing pentest page - copy kubectl command button

Copy this command and paste it into a terminal with Kubectl. Ensure that your current Kubectl context is set to your desired cluster. This one-time command will launch the Pentest using the NodeZero Pentest Kubernetes Custom Resource Definition.

What permissions are needed to deploy the pentest?

An example ClusterRole CRD with the needed permissions can be found here.

Real-Time View will show up, from where you can Inject Credentials and monitor pentest progress.

Pentest page showing the new Kubernetes pentest at the top of the table.

You've started a Kubernetes Pentest

NodeZero sends an email once the Kubernetes Pentest completes.

Uninstall the NodeZero Operator

If you've used the helm upgrade command outlined above in Install Operator, you have the option to later uninstall the operator as follows:

  1. Verify releases with: helm ls -n <the-namespace>. (This will typically be: helm ls -n nodezero.)

  2. Uninstall the operator with a command of the form: helm uninstall nodezero-operator -n nodezero.