GKE clusters whose nodes carry public IP addresses
What does ZopNight detect here?
GKE nodes in a non-private cluster each hold an external IP, exposing every node directly to the internet. ZopNight rule RC-1222 flags clusters lacking the discoverer's private_cluster_enabled=true stamp, derived from privateClusterConfig.enablePrivateNodes. Remediation means recreating the cluster with --enable-private-nodes plus Cloud NAT for egress.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1222 |
| Category | compliance |
| Severity | high |
| Metric | none — pure configuration read |
| Source | gke_private_cluster.go |
Where it applies
Fixing this means a new cluster
Private nodes are a creation-time property of a GKE cluster. A cluster built without --enable-private-nodes cannot be converted; the remediation is a replacement cluster with private nodes on, Cloud NAT configured for outbound access (private nodes lose their direct path to the internet for image pulls and package downloads), and a workload migration to close it out. That cost profile is why this finding tends to sit open longest of the GKE set, and why the sensible move is bundling it with the other recreate-only fixes (VPC-native networking, in particular) into a single rebuild.
The exposure: a node fleet with internet faces
In a non-private cluster every node carries an external IP. Each node is then a direct member of the internet-facing attack surface: its kubelet port, its SSH daemon, and any hostPort a workload opens are one firewall mistake away from public reachability, multiplied by however many nodes autoscaling runs. Private nodes remove the entire category: with only internal IPs, nodes are unreachable from outside regardless of what a firewall rule accidentally allows. Node egress changes too, which is operationally useful: all outbound traffic funnels through Cloud NAT, giving you a fixed set of egress IPs that third parties can allowlist.
Inference, anchored: how RC-1222 decides
The discoverer writes private_cluster_enabled=true from privateClusterConfig.enablePrivateNodes, and writes it only when true. Rule RC-1222 therefore infers non-private clusters from the stamp’s absence rather than proving them from an explicit false. The gate is anchored on k8s_version, a key the same enricher always stamps: a resource without it was never enriched as a GKE cluster and is skipped, so the inference only runs on clusters the discoverer actually characterised. An earlier tag-based gate read a key no producer wrote and was dead on live data.
Check the flag directly
gcloud container clusters describe my-cluster --location us-central1 \ --format='value(privateClusterConfig.enablePrivateNodes)'Empty output means public nodes. Note the flag covers nodes only. The control-plane endpoint’s exposure is a separate setting, judged by the master-authorized-networks rule, and a cluster can fail either one independently.