Skip to main content

More Info:

Worker nodes should be deployed in private subnets without public IPs so they are not directly reachable from the internet. Combine with a NAT/Service Gateway for outbound traffic.

Risk Level

High

Address

Compliance, Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Using Console

Below are the remediation steps in the OCI Console to ensure OKE node pools use private nodes (no public IPs, only private subnets).

1. Prerequisites: Ensure You Have Private Subnets

  1. In the OCI Console, go to Networking → Virtual Cloud Networks.
  2. Select the VCN used by your OKE cluster.
  3. Under Subnets, verify you have:
    • One or more private subnets (no Internet Gateway in their route table, typically using a NAT Gateway for outbound access).
    • Proper security lists / NSGs to allow:
      • Node-to-node traffic
      • Node-to-control-plane traffic (per OKE docs)
  4. If you don’t have a private subnet:
    1. Click Create Subnet.
    2. Choose:
      • Private Subnet: Yes
      • Associate with the VCN used by the OKE cluster
      • Attach route table that sends 0.0.0.0/0 to a NAT Gateway (not Internet Gateway).
    3. Save the subnet.

2. Confirm Current Node Pool Configuration

  1. Go to Developer Services → Kubernetes Clusters (OKE).
  2. Select your Cluster.
  3. Click Node Pools.
  4. For each node pool:
    • Check the Subnets column.
    • Open the node pool, and in the Details panel verify:
      • Whether it is using public subnets.
      • Whether nodes have public IP addresses (this is typically controlled by the subnet type and advanced node settings).
You cannot “flip” an existing pool from public to private; you must create a new private node pool and migrate workloads.

3. Create a New Private Node Pool

  1. On the Node Pools tab of the cluster, click Create node pool.
  2. Fill in:
    • Name: e.g., private-node-pool.
    • Kubernetes version: same as the cluster or as required.
    • Node shape and Image: match or improve upon current node pool.
  3. Under Placement:
    • Choose the same Availability Domains / Fault Domains as required.
    • In Subnets, select only private subnets (created in step 1).
  4. Under Node configuration / Node metadata & networking (wording may vary slightly):
    • Ensure Assign public IP addresses (or similar option) is unchecked/disabled.
    • Confirm that Network security groups or Security lists allow needed traffic.
  5. Set the desired Node count.
  6. Click Create and wait for the node pool status to become Active and nodes to be Ready.

4. Migrate Workloads to the Private Node Pool

Use kubectl (or OKE Cloud Shell) for this part.
  1. Label the new node pool’s nodes (optional but helpful):
  2. If your workloads use node selectors, affinities, or taints:
    • Update Deployments/StatefulSets/DaemonSets to schedule to the new nodes (e.g., nodeSelector: { nodepool: private }).
  3. Gradually cordon and drain old (public) nodes:
  4. Verify all Pods are running on the new private nodes:

5. Delete the Old Public Node Pool

  1. In OCI Console, return to the Node Pools tab for your cluster.
  2. Confirm:
    • No workloads are running on the old node pool’s nodes.
  3. Click on the old (public) node pool.
  4. Click Delete and confirm.

6. Validate Private-Only Access

  1. In Compute → Instances, locate instances from the new node pool:
    • Confirm each instance has no public IP.
    • Confirm they are placed in your private subnet.
  2. Confirm cluster behavior:
    • Pods and services function normally.
    • Outbound access (e.g., to Docker Hub, OCI Registry) works via the NAT Gateway, not Internet Gateway.
  3. If you use a bastion host or VPN / FastConnect, make sure admins can still reach nodes if required (SSH via private IP only).

Result: Your OKE node pools now use private nodes (in private subnets, no public IPs) as required.
To use private nodes in an OKE node pool via OCI CLI, you must:
  1. Disable public IP assignment on the node pool, and
  2. Ensure the node pool uses private subnets (no internet gateway attached).
Below are the key steps and example commands.

1. Prerequisites

  • OCI CLI configured with appropriate privileges.
  • OKE Cluster OCID.
  • Private subnet OCIDs in the cluster VCN (subnets should not be associated to an Internet Gateway; use NAT Gateway for outbound if needed).

2. Identify the Node Pool

Check:
  • nodeConfigDetails.isPublicIpEnabled
  • nodeConfigDetails.placementConfigs[].subnetId

3. Update Node Pool to Disable Public IPs

isPublicIpEnabled must be false.Example:
Notes:
  • size must match or be set to your desired node count.
  • Ensure subnetId references a private subnet.
  • This setting applies to new/replaced nodes; existing ones keep their current IPs until cycled.

4. Move Nodes Fully to Private Subnets (If Needed)

If your current nodes are in public subnets or already have public IPs, you must replace them after updating the pool:
Before replacing, you should cordon & drain via kubectl to avoid workload disruption.

5. (Alternative) Create a New Private Node Pool

If you prefer not to modify the existing pool:
Then:
  1. Drain workloads from the old node pool.
  2. Delete the old (public) node pool:

Compliance check:
After changes, confirm:
isPublicIpEnabled should be false, and subnets should be private subnets only.
To use private nodes in an OCI OKE node pool, you must ensure that:
  1. The node pool’s worker nodes are placed in private subnets (no Internet Gateway route).
  2. Existing node pools that use public subnets are migrated to new node pools in private subnets.
Below is a step‑by‑step outline, followed by a Python example using the OCI SDK.

1. Prerequisites

  • Python 3.x
  • oci SDK installed:
  • OCI config file set up (~/.oci/config) and a profile (e.g., DEFAULT) with permissions for:
    • ContainerEngineClient (OKE)
    • VirtualNetworkClient (networking)

2. Network Setup (ensure private subnets)

  1. Identify / create a VCN.
  2. Create or identify a private subnet:
    • Subnet is in the same VCN and AD as the cluster.
    • Subnet uses a route table without an Internet Gateway (use a NAT gateway or Service Gateway for outbound if needed).
    • Proper security lists / NSGs are applied.
Python (optional) to verify that a subnet is private (no route to Internet Gateway):
Create a new private subnet if needed and use its subnet_id for the node pool.

3. Create a New Private Node Pool with Python

You cannot “flip” a public node pool to private directly; you typically:
  • Create a new node pool using private subnets.
  • Cordon & drain workloads from the old node pool.
  • Delete the old node pool.
Key point: Using a private subnet (no Internet Gateway in its route table) ensures nodes get only private IPs. That is what makes the node pool “private” in OKE.

4. Migrate Workloads and Remove Old Public Node Pool

Once the new private node pool is active:
  1. Update your cluster’s node selectors / taints so workloads can run on the new nodes.
  2. Cordon and drain nodes in the old (public) node pool from kubectl:
  3. Delete the old node pool via Python:

5. Optional: Enforce Private-Only Node Pools (Programmatically)

If you want to ensure that new node pools are always private, you can add a check in your automation that:
  • Validates subnet_id is private (no IGW route) using the helper in step 2.
  • Rejects or fails creation if any subnet is public.
This completes the Python-based remediation: all OKE node pools use private subnets, so nodes are private-only.
Changing an existing node pool to use a different (private) subnet will force replacement of the node pool (nodes are recreated), and changing prohibit_public_ip_on_vnic on an existing subnet forces subnet replacement; plan this to avoid outages.After updating, terraform plan should show:
  • prohibit_public_ip_on_vnic = true being set on the worker subnet (or a new private subnet created), and
  • the oci_containerengine_node_pool using that private subnet ID in its placement_configs.