OCI OKE Anonymous Requests to Kubelet Server Should Be
More Info:
When anonymous authentication is enabled, requests not rejected by other authenticators are treated as anonymous and may reach kubelet APIs. Disabling anonymous auth is a hard requirement to prevent unauthenticated control-plane access on nodes.
Risk Level
Critical
Address
Compliance, Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Using Console
To disable anonymous requests to the kubelet in OCI OKE using the OCI Console, you need to update your node pool configuration so kubelet runs with anonymous authentication turned off. In most cases this is done by updating (or recreating) the node pool with the correct kubelet config.
Below are the steps in the OCI Console.
1. Confirm your OKE cluster and node pool
- Sign in to the OCI Console.
- Open the navigation menu → Developer Services → Kubernetes Clusters (OKE).
- Select the Compartment where your cluster resides.
- Click your cluster name.
- In the cluster details page, go to the Node Pools tab.
- Identify the node pool(s) whose kubelet configuration you want to fix.
2. Check if node pool kubelet configuration is editable
For many OKE versions, key kubelet security options are controlled via the Kubelet configuration section on the node pool.
- In the Node Pools tab, click the node pool name.
- Click Edit or Update (top-right of the node pool details page).
- Expand Advanced Options → Kubelet configuration (or similar wording).
If the console exposes a checkbox or field related to anonymous authentication, use it (e.g. something like Disable anonymous access / Anonymous auth).
If not, you’ll need to specify a kubelet config block (JSON/YAML) through the console field provided.
3. Set kubelet to disallow anonymous auth
Within the Kubelet configuration section, you must ensure that kubelet is started with --anonymous-auth=false. Depending on what your OKE version exposes:
- If there is a toggle/checkbox for anonymous auth:
- Turn off / disable anonymous authentication (or enable “Disable anonymous access”).
- If there is a raw kubelet config field:
- Add or ensure a flag or parameter equivalent to:
anonymousAuth: false
or- an extra-argument that sets
--anonymous-auth=false.
- Add or ensure a flag or parameter equivalent to:
Save/update the node pool when done.
Note: Exact field names can differ slightly by OKE/Kubernetes version. Look for anything documented or labeled around “anonymous authentication”, “anonymous access”, or kubelet security options.
4. Apply changes to worker nodes
Changing the node pool configuration alone does not always immediately reconfigure existing worker nodes. You typically need to recreate the worker nodes so they are started with the updated kubelet settings.
You have two main options:
Option A – Rolling replacement within the same node pool (if supported):
- After saving the updated node pool configuration, scale the node pool up by adding new nodes.
- Wait for the new nodes to become Active and join the cluster.
- Cordon and drain old nodes (from
kubectl):kubectl cordon <old-node-name>kubectl drain <old-node-name> --ignore-daemonsets --delete-emptydir-data - In the OCI Console, terminate the old nodes from the node pool.
- Repeat for each old node until all nodes in the node pool are newly created with the updated kubelet config.
Option B – Create a new node pool (cleaner approach):
- In the cluster page, go to Node Pools → Create node pool.
- Configure it identically (shape, images, labels, taints, etc.) but:
- Under Advanced Options → Kubelet configuration, set anonymous auth to disabled as described above.
- Create the node pool and wait for nodes to become Active.
- Use
kubectlto cordon and drain nodes from the old node pool, then:- In the console, delete the old node pool once workloads are safely running on the new pool.
5. Verify that anonymous auth is disabled
After nodes with the new configuration are running:
- Get the node IPs:
kubectl get nodes -o wide
- From a pod (or a secure bastion) with network access to node IPs, verify kubelet no longer accepts anonymous requests (for example, an unauthenticated curl to kubelet’s read-only port or API should now fail).
If available in your security tooling or benchmark scanner, re-run the CIS / security check that reported “Anonymous Requests to Kubelet Server Should Be Disabled” to confirm it passes.
If you share the exact OKE and Kubernetes version you’re running, I can give the precise field name/syntax for the kubelet configuration in your console view.
Using CLI
To disable anonymous requests to the kubelet on OKE worker nodes, you need to change the kubelet configuration on each node so that:
--anonymous-auth=falseis set (or)authentication: anonymous: enabled: falseis set in the kubelet config file
OKE does not expose kubelet flags directly via the OCI CLI, so you use the OCI CLI to discover and SSH to nodes, then change the kubelet config on each node.
Below are step‑by‑step commands and actions.
1. Get the node pool and node OCIDs
# Set variables
COMPARTMENT_OCID="<your_compartment_ocid>"
CLUSTER_OCID="<your_oke_cluster_ocid>"
# List node pools for a cluster
oci ce node-pool list \
--compartment-id "$COMPARTMENT_OCID" \
--cluster-id "$CLUSTER_OCID" \
--all
Note the id (nodePoolId) you want to remediate.
NODE_POOL_OCID="<your_node_pool_ocid>"
# Get node pool details (to see instance OCIDs)
oci ce node-pool get --node-pool-id "$NODE_POOL_OCID" \
--query "data.nodes[].id" --raw-output
This returns the compute instance OCIDs for the worker nodes.
2. Get each node’s public IP (via OCI CLI)
For each worker instance OCID:
INSTANCE_OCID="<worker_instance_ocid>"
# Get VNIC attachment
VNIC_ID=$(oci compute vnic-attachment list \
--compartment-id "$COMPARTMENT_OCID" \
--instance-id "$INSTANCE_OCID" \
--query "data[0].\"vnic-id\"" \
--raw-output)
# Get public IP
oci network vnic get --vnic-id "$VNIC_ID" \
--query "data.\"public-ip\"" \
--raw-output
Use that IP for SSH.
3. SSH to each node
ssh -i <path_to_private_key> opc@<node_public_ip>
(Use ubuntu or other user if your image differs.)
4. Update kubelet config on the node
On each node:
-
Locate the kubelet config file (for OKE it is usually
/var/lib/kubelet/config.yaml):sudo cat /var/lib/kubelet/config.yaml | grep -A3 authentication -
Ensure anonymous auth is disabled. The
authenticationsection should look like:authentication:anonymous:enabled: falsewebhook:enabled: truecacheTTL: 2m0sIf
anonymous.enabledistrueor missing, edit the file:sudo vi /var/lib/kubelet/config.yamlAdd/modify:
authentication:anonymous:enabled: falseIf the node is using flags instead of config.yaml, edit the kubelet systemd unit or environment file (often
/etc/systemd/system/kubelet.service.d/10-kubelet-args.confor similar) and ensure:--anonymous-auth=false -
Reload systemd and restart kubelet:
sudo systemctl daemon-reloadsudo systemctl restart kubelet -
Verify kubelet is healthy:
sudo systemctl status kubelet
Repeat steps 3–4 for each worker node in the node pool.
5. (Optional) Bake this into node boot/launch
Because OKE re‑creates worker nodes (e.g., during scaling or upgrades), you should ensure new nodes get the same setting automatically. You can do this by:
- Using a custom image where
/var/lib/kubelet/config.yamlalready hasanonymous.enabled: false, or - Using cloud-init/bootstrapping scripts in the instance’s metadata.
Using OCI CLI to update instance metadata for the node pool’s instance configuration (template):
-
Identify the instance configuration used by the node pool:
oci ce node-pool get --node-pool-id "$NODE_POOL_OCID"Look for
nodeConfigDetails→placementConfigs/ instance details, then trace back to the instance configuration (if used) via Compute → Instance Configurations. -
Update that instance configuration’s metadata to include a cloud-init script that enforces the kubelet config on boot.
Example (pseudo):
oci compute instance-configuration update \
--instance-configuration-id <ocid> \
--instance-details '{
"launchDetails": {
"metadata": {
"user_data": "'"$(base64 -w0 kubelet-hardening.yaml)"'"
}
}
}'
Where kubelet-hardening.yaml is a cloud-init script that edits /var/lib/kubelet/config.yaml to set authentication.anonymous.enabled: false and restarts kubelet.
6. Validate from the cluster
From a machine with kubectl access:
kubectl get nodes
kubectl describe node <node_name> | grep -i kubelet
Optionally, from within the node, query the kubelet config endpoint and ensure anonymous access fails (or needs auth).
If you share your specific OKE node OS image and version (Oracle Linux vs Ubuntu, managed vs custom), I can give you the exact file paths and edit commands for that image.
Using Python
To disable anonymous requests to the kubelet for Oracle OKE using Python, you need to:
- Configure the kubelet on each node pool to run with
--anonymous-auth=false(and preferably disable the read-only port). - Do this via an OKE Node Pool update using the OCI Python SDK (which will roll the nodes).
Below is a minimal, end‑to‑end example.
1. Prerequisites
- Python 3.x
- OCI Python SDK:
pip install oci
- An OCI config file (
~/.oci/config) with a profile that has:- Permission to
MANAGEclusters and node pools in the target compartment.
- Permission to
- Your OKE cluster OCID and/or node pool OCIDs.
2. High-level actions
For each node pool in your OKE cluster:
- Get the node pool definition.
- Update its kubelet configuration to:
anonymous-auth = false- (Optionally)
read-only-port = 0for extra hardening.
- Call
UpdateNodePoolvia the OCI Container Engine client. - Wait for the node pool to complete its rolling update.
3. Example Python script
This example:
- Lists node pools for a given cluster.
- Updates each node pool’s kubelet config to disable anonymous auth.
Adjust values in the CONFIG section.
import oci
from oci.container_engine import ContainerEngineClient
from oci.container_engine.models import (
UpdateNodePoolDetails,
NodePoolNodeConfigDetails,
KubeletConfig
)
# ---------------- CONFIG ----------------
OCI_PROFILE = "DEFAULT" # profile from ~/.oci/config
CLUSTER_OCID = "<your_cluster_ocid>" # e.g. ocid1.cluster.oc1...
# If you already know a specific node pool OCID, you can skip cluster listing
# and just put it in NODE_POOL_OCIDS and comment out the listing logic.
NODE_POOL_OCIDS = [] # leave empty to fetch all node pools from the cluster
COMPARTMENT_OCID = "<compartment_ocid>" # only needed if discovering node pools
# ----------------------------------------
def get_container_engine_client():
config = oci.config.from_file(profile_name=OCI_PROFILE)
return ContainerEngineClient(config)
def list_node_pools_for_cluster(client, cluster_id, compartment_id):
node_pools = []
list_resp = client.list_node_pools(
compartment_id=compartment_id,
cluster_id=cluster_id
)
node_pools.extend(list_resp.data)
# Handle pagination if needed:
while list_resp.has_next_page:
list_resp = client.list_node_pools(
compartment_id=compartment_id,
cluster_id=cluster_id,
page=list_resp.next_page
)
node_pools.extend(list_resp.data)
return node_pools
def update_node_pool_kubelet_config(client, node_pool_id):
# Get current node pool
np = client.get_node_pool(node_pool_id).data
# Build new kubelet config
# Here we explicitly disable anonymous-auth
# and optionally disable the read-only port.
kubelet_config = KubeletConfig(
anonymous_auth=False,
# Optional hardening:
# read_only_port_enabled=False
)
# Keep existing node config details but override kubelet_config
current_node_config = np.node_config_details
if current_node_config is None:
current_node_config = NodePoolNodeConfigDetails()
new_node_config = NodePoolNodeConfigDetails(
size=current_node_config.size,
nsg_ids=current_node_config.nsg_ids,
subnet_ids=current_node_config.subnet_ids,
# IMPORTANT: set the kubelet config here:
kubelet_config=kubelet_config,
# Preserve other fields if you’re using them:
placement_configs=current_node_config.placement_configs,
ssh_public_key=current_node_config.ssh_public_key,
is_pv_encryption_in_transit_enabled=getattr(
current_node_config, "is_pv_encryption_in_transit_enabled", None
)
)
update_details = UpdateNodePoolDetails(
name=np.name,
kubernetes_version=np.kubernetes_version,
node_shape=np.node_shape,
node_config_details=new_node_config,
node_eviction_node_pool_settings=np.node_eviction_node_pool_settings,
initial_node_labels=np.initial_node_labels
)
print(f"Updating node pool {node_pool_id} to disable kubelet anonymous-auth...")
resp = client.update_node_pool(node_pool_id=node_pool_id, update_node_pool_details=update_details)
work_request_id = resp.headers.get('opc-work-request-id')
print(f"Submitted update. Work request: {work_request_id}")
# Optionally, wait for completion
if work_request_id:
work_request_client = oci.container_engine.ContainerEngineClientCompositeOperations(client)
print("Waiting for node pool update to complete...")
work_request_client.wait_for_work_request(work_request_id)
print(f"Node pool {node_pool_id} update completed.")
return resp
def main():
client = get_container_engine_client()
# Discover node pools if not explicitly provided
node_pool_ids = NODE_POOL_OCIDS.copy()
if not node_pool_ids:
node_pools = list_node_pools_for_cluster(
client,
cluster_id=CLUSTER_OCID,
compartment_id=COMPARTMENT_OCID
)
node_pool_ids = [np.id for np in node_pools]
if not node_pool_ids:
print("No node pools found to update.")
return
for np_id in node_pool_ids:
update_node_pool_kubelet_config(client, np_id)
if __name__ == "__main__":
main()
4. Notes
- Updating node pools this way typically triggers a rolling replacement of nodes; plan for impact.
- Ensure your OKE version/API supports
kubeletConfigon node pools; if it doesn’t, you must instead use a custom cloud-init or image that sets--anonymous-auth=falseon kubelet before OKE manages the node. - After completion, validate on a node:
ps aux | grep kubelet | grep anonymous-auth# should show --anonymous-auth=false
If you share your current OKE version and a sample get_node_pool output, I can tailor the exact fields to your environment.
Using Terraform
resource "oci_containerengine_node_pool" "OKE_NODEPOOL" {
# Replace OKE_NODEPOOL with your node pool name
# Set these to match your existing configuration
cluster_id = oci_containerengine_cluster.OKE_CLUSTER.id
compartment_id = var.COMPartment_OCID
kubernetes_version = "YOUR_K8S_VERSION"
name = "YOUR_NODEPOOL_NAME"
node_shape = "YOUR_NODE_SHAPE"
# ... other existing arguments like node_config_details, initial_node_labels, etc.
kubelet_config {
# Disable anonymous requests to the kubelet server
is_anonymous_auth_enabled = false
}
}
Changing kubelet_config.is_anonymous_auth_enabled does not force replacement of the node pool resource itself, but OKE will roll nodes to apply the new kubelet configuration (expect node recreation / disruption during the rollout).
To verify, terraform plan should show an in-place update on oci_containerengine_node_pool.OKE_NODEPOOL with kubelet_config.is_anonymous_auth_enabled changing from true (or null) to false.