OCI OKE Should Use Network Policies to Control Traffic
More Info:
Define NetworkPolicy resources to allow only required ingress and egress per namespace and workload. Default-deny policies prevent compromised pods from pivoting laterally to other services or the internet.
Risk Level
High
Address
Compliance, Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Using Console
To meet “OKE should use Network Policies to control traffic,” you need to:
-
Make sure your OKE cluster supports network policies
- In OCI Console: go to Developer Services → Kubernetes Clusters (OKE).
- Open your cluster.
- On the Cluster Information page, check:
- Cluster Type must be VCN-native (pod VNIC) (network policies are not supported on “Classic” clusters).
- If your cluster is “Classic”, you must:
- Create a new VCN-native OKE cluster and migrate workloads (there’s no in-place conversion).
-
Enable Network Policies on the OKE cluster (Console)
- In the same cluster page, click Edit Details (or Update Cluster depending on UI version).
- Look for Network Configuration / Network Policies section.
- Enable or check:
- Kubernetes Network Policy Enforcement (or similar wording).
- Save the changes.
- Wait for the cluster state to return to Active.
-
Ensure node pools are updated
- Within the cluster page, go to Node Pools.
- For each node pool:
- Check Kubernetes version and image; ensure they meet the minimum version required for network policy support (generally any recent OKE version will).
- If needed, click Edit / Upgrade to update node pool version and image.
- Allow node pools to complete upgrade / rolling replacement.
-
Verify network plugin / CNI
- On the cluster page, confirm that it uses VCN-native CNI (Pod VNICs). This is implicit for VCN-native clusters.
- Classic Flannel-based clusters do not support network policies.
-
Create Kubernetes NetworkPolicy objects (kubectl) This part is not done in the OCI Console UI; you use kubectl against your OKE cluster, but it’s required to actually enforce traffic rules.
5.1. Get kubeconfig from OCI Console
- In your cluster page, click Access Cluster.
- Follow the instructions to:
- Download/update your kubeconfig (e.g., using the Cloud Shell or your local machine).
- Example (Cloud Shell):
oci ce cluster create-kubeconfig \--cluster-id <your-cluster-ocid> \--file $HOME/.kube/config \--region <your-region> \--token-version 2.0.0 \--kube-endpoint PUBLIC_ENDPOINT
- Then:
kubectl get nodes
5.2. Apply an initial restrictive NetworkPolicy
- Example: default deny all ingress within a namespace:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: default-deny-ingressnamespace: defaultspec:podSelector: {}policyTypes:- Ingress
- Save as
default-deny-ingress.yamland apply:kubectl apply -f default-deny-ingress.yaml
5.3. Add allow rules as needed
- Example: allow ingress to pods labeled
app: myapponly from pods labeledrole: frontend:apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: allow-frontend-to-myappnamespace: defaultspec:podSelector:matchLabels:app: myapppolicyTypes:- Ingressingress:- from:- podSelector:matchLabels:role: frontend - Apply:
kubectl apply -f allow-frontend-to-myapp.yaml
-
Validate enforcement
- From Cloud Shell or a test pod:
- Confirm that denied traffic is blocked and allowed traffic works:
kubectl run test --rm -it --image=alpine -- sh# Inside pod, try to curl or nc target services
- Confirm that denied traffic is blocked and allowed traffic works:
- From Cloud Shell or a test pod:
Summary of remediation in OCI Console:
- Ensure cluster is VCN-native.
- In Cluster → Edit Details, enable Network Policy enforcement.
- Update node pools if needed.
- Then define and apply Kubernetes NetworkPolicy resources (kubectl) to actually control pod-to-pod and namespace traffic.
Using CLI
In OCI Container Engine for Kubernetes (OKE), Calico network policies must be enabled at cluster creation time. You cannot turn them on for an existing cluster. So “remediation” means:
- Verify the current cluster’s setting
- Create a new OKE cluster with network policies enabled (via OCI CLI)
- Migrate workloads and delete the old cluster
Below are the key steps and OCI CLI examples.
1. Verify if Network Policy is Enabled on Current Cluster
CLUSTER_ID="<your-existing-cluster-ocid>"
oci ce cluster get \
--cluster-id "$CLUSTER_ID" \
--query "data.kubernetes-network-config.network-policy-config" \
--output json
If you see "isNetworkPolicyEnabled": false or null, it is not enabled and cannot be changed on this cluster.
2. Create a New OKE Cluster with Network Policies Enabled
You must use the --options / kubernetesNetworkConfig with networkPolicyConfig set to true.
Prepare a JSON file, e.g. cluster-options.json:
{
"kubernetesNetworkConfig": {
"podsCidr": "10.244.0.0/16",
"servicesCidr": "10.96.0.0/16",
"networkPolicyConfig": {
"isNetworkPolicyEnabled": true
}
}
}
Then run:
COMPARTMENT_ID="<compartment-ocid>"
VCN_ID="<vcn-ocid>"
SUBNET_IDS='["<subnet-ocid-1>","<subnet-ocid-2>"]' # for LB / control plane, etc.
CLUSTER_NAME="oke-with-network-policy"
K8S_VERSION="<desired-k8s-version>" # e.g. v1.29.2
oci ce cluster create \
--name "$CLUSTER_NAME" \
--compartment-id "$COMPARTMENT_ID" \
--vcn-id "$VCN_ID" \
--kubernetes-version "$K8S_VERSION" \
--endpoint-config '{"isPublicIpEnabled": false}' \
--options file://cluster-options.json \
--kms-key-id "<optional-kms-key-ocid>" \
--freeform-tags '{"env":"prod"}'
Check that network policies are enabled:
NEW_CLUSTER_ID="<new-cluster-ocid>"
oci ce cluster get \
--cluster-id "$NEW_CLUSTER_ID" \
--query "data.kubernetes-network-config.network-policy-config" \
--output json
You should see:
{
"isNetworkPolicyEnabled": true
}
3. Create Node Pool(s) for the New Cluster
NODEPOOL_NAME="np-with-network-policy"
NODE_SHAPE="VM.Standard.E4.Flex"
NODE_IMAGE_ID="<node-image-ocid>"
NODE_SUBNET_IDS='["<worker-subnet-ocid-1>","<worker-subnet-ocid-2>"]'
oci ce node-pool create \
--compartment-id "$COMPARTMENT_ID" \
--cluster-id "$NEW_CLUSTER_ID" \
--name "$NODEPOOL_NAME" \
--kubernetes-version "$K8S_VERSION" \
--node-shape "$NODE_SHAPE" \
--node-source-details "{\"sourceType\":\"IMAGE\",\"imageId\":\"$NODE_IMAGE_ID\"}" \
--subnet-ids "$NODE_SUBNET_IDS" \
--node-config-details '{"size":3}'
Wait until the node pool is ACTIVE:
oci ce node-pool get --node-pool-id "<node-pool-ocid>" --query "data.lifecycle-state"
4. Point kubectl to the New Cluster
# Generate kubeconfig for new cluster
oci ce cluster create-kubeconfig \
--cluster-id "$NEW_CLUSTER_ID" \
--file $HOME/.kube/config-new \
--region "<region>" \
--token-version 2.0.0 \
--kube-endpoint PRIVATE
export KUBECONFIG=$HOME/.kube/config-new
kubectl get nodes
5. Deploy/Enforce Kubernetes NetworkPolicies
Network policies themselves are standard Kubernetes resources and are applied with kubectl, not OCI CLI. Example:
# deny-all-default.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
kubectl apply -f deny-all-default.yaml
Then add more granular NetworkPolicy manifests to allow needed traffic.
6. Migrate Workloads and Delete Old Cluster
- Export and reapply manifests (or use Helm/ArgoCD/etc.) into the new cluster.
- Verify apps and traffic behavior under network policies.
- Delete old resources:
OLD_CLUSTER_ID="<old-cluster-ocid>"
# Delete old node pools first (if still present)
oci ce node-pool list \
--compartment-id "$COMPARTMENT_ID" \
--cluster-id "$OLD_CLUSTER_ID" \
--query "data[].id" \
--output tsv | while read NP; do
oci ce node-pool delete --node-pool-id "$NP" --force --wait-for-state SUCCEEDED
done
# Delete the old cluster
oci ce cluster delete \
--cluster-id "$OLD_CLUSTER_ID" \
--force \
--wait-for-state SUCCEEDED
If you share your current cluster’s oci ce cluster get output (redacted), I can give you an exact cluster-options.json and CLI command tailored to your environment.
Using Python
To remediate this, you need to define and apply Kubernetes NetworkPolicy resources to your OKE cluster. The Python part is about programmatically creating/applying those policies using the Kubernetes Python client.
Below are the minimal practical steps.
1. Prerequisites
- An existing OKE cluster with:
- Worker nodes running
kubectlaccess working from your machine
kubeconfigfor the OKE cluster (usually generated via OCI Console or CLI).- Python packages installed:
pip install kubernetes
(You only need the OCI Python SDK if you also want to automate kubeconfig generation or cluster creation.)
2. Ensure Network Policies Are Supported/Enabled in the Cluster
NetworkPolicies are a Kubernetes feature; OKE supports them when using a compatible CNI/network plugin.
From the Kubernetes side, you can check quickly:
kubectl api-resources | grep networkpolicies
You should see:
networkpolicies netpol networking.k8s.io/v1 true NetworkPolicy
If that’s missing, the cluster/network setup doesn’t support network policies and must be re-created or reconfigured via OCI (do that via console/OCI CLI/SDK according to Oracle docs).
Assuming the resource exists, continue.
3. Python: Connect to OKE via Kubernetes Client
from kubernetes import client, config
# Load local kubeconfig (pointing to your OKE cluster)
config.load_kube_config() # or load_incluster_config() if running inside the cluster
# Create API client for NetworkPolicy
netpol_api = client.NetworkingV1Api()
If your kubeconfig isn’t in the default path, pass it explicitly:
config.load_kube_config(config_file="/path/to/oke-kubeconfig")
4. Define a “Default Deny” NetworkPolicy (Ingress + Egress)
This enforces that no pod in a namespace can talk to anything unless explicitly allowed by additional NetworkPolicies.
Example for namespace production:
from kubernetes import client
namespace = "production"
default_deny_netpol = client.V1NetworkPolicy(
metadata=client.V1ObjectMeta(
name="default-deny-all",
namespace=namespace,
),
spec=client.V1NetworkPolicySpec(
pod_selector=client.V1LabelSelector( # selects all pods in namespace
match_labels={}
),
policy_types=["Ingress", "Egress"],
ingress=[], # deny all ingress
egress=[], # deny all egress
),
)
Apply it:
try:
netpol_api.create_namespaced_network_policy(
namespace=namespace,
body=default_deny_netpol,
)
print("Default deny NetworkPolicy created.")
except client.exceptions.ApiException as e:
if e.status == 409:
print("Default deny NetworkPolicy already exists.")
else:
raise
5. Define an Allow Policy (Example: Allow HTTP from Frontend to Backend)
Suppose:
- All frontend pods have label:
app: frontend - All backend pods have label:
app: backend - You want to allow frontend → backend on port 8080 only (in namespace
production).
allow_frontend_to_backend = client.V1NetworkPolicy(
metadata=client.V1ObjectMeta(
name="allow-frontend-to-backend",
namespace=namespace,
),
spec=client.V1NetworkPolicySpec(
pod_selector=client.V1LabelSelector(
match_labels={"app": "backend"} # this policy applies to backend pods
),
policy_types=["Ingress"],
ingress=[
client.V1NetworkPolicyIngressRule(
_from=[
client.V1NetworkPolicyPeer(
pod_selector=client.V1LabelSelector(
match_labels={"app": "frontend"}
)
)
],
ports=[
client.V1NetworkPolicyPort(
port=8080,
protocol="TCP",
)
]
)
]
)
)
try:
netpol_api.create_namespaced_network_policy(
namespace=namespace,
body=allow_frontend_to_backend,
)
print("Allow frontend-to-backend NetworkPolicy created.")
except client.exceptions.ApiException as e:
if e.status == 409:
print("Allow NetworkPolicy already exists.")
else:
raise
6. (Optional) Apply Policies from YAML Using Python
If you prefer writing YAML files and applying them via Python:
netpol-default-deny.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress: []
egress: []
Python to apply:
from kubernetes import client, config, utils
from kubernetes.client import api_client
config.load_kube_config()
k8s_client = api_client.ApiClient()
utils.create_from_yaml(k8s_client, "netpol-default-deny.yaml")
7. Verification
After applying via Python:
kubectl get networkpolicy -n production
kubectl describe networkpolicy default-deny-all -n production
Test connectivity (e.g., with temporary pods) to verify that only the allowed traffic flows.
If you share your specific traffic matrix (which pods/services should be allowed to talk to which), I can provide tailored Python code to generate those NetworkPolicies.
Using Terraform
# This cannot be remediated on oci_containerengine_cluster itself;
# NetworkPolicy is a Kubernetes resource and must be applied via the Kubernetes API.
# Configure the Kubernetes provider against your OKE cluster
provider "kubernetes" {
host = var.OKE_CLUSTER_ENDPOINT # e.g. from oci_containerengine_cluster.endpoint
cluster_ca_certificate = base64decode(var.OKE_CLUSTER_CA) # e.g. from oci_containerengine_cluster.certificate_authority
token = var.OKE_CLUSTER_BEARER_TOKEN # or exec/auth provider
}
############################################################
# 1. Default-deny all ingress in a namespace
############################################################
resource "kubernetes_network_policy_v1" "ns_default_deny_ingress" {
metadata {
name = "default-deny-ingress"
namespace = "TARGET_NAMESPACE" # replace with the namespace to protect
}
spec {
pod_selector {} # selects all pods in the namespace
ingress {} # empty = deny all ingress
policy_types = ["Ingress"]
}
}
############################################################
# 2. Default-deny all egress in a namespace
############################################################
resource "kubernetes_network_policy_v1" "ns_default_deny_egress" {
metadata {
name = "default-deny-egress"
namespace = "TARGET_NAMESPACE" # same namespace as above
}
spec {
pod_selector {} # selects all pods in the namespace
egress {} # empty = deny all egress
policy_types = ["Egress"]
}
}
############################################################
# 3. Allow only required ingress to a specific app
############################################################
resource "kubernetes_network_policy_v1" "app_allow_ingress" {
metadata {
name = "allow-app-ingress"
namespace = "TARGET_NAMESPACE" # namespace where the app runs
}
spec {
pod_selector {
match_labels = {
app = "APP_LABEL" # replace with label selecting the workload (e.g. "web")
}
}
ingress {
from {
namespace_selector {
match_labels = {
name = "ALLOWED_CALLER_NAMESPACE" # namespace allowed to reach this app
}
}
}
ports {
port = 80
protocol = "TCP"
}
}
policy_types = ["Ingress"]
}
}
############################################################
# 4. Allow only required egress from a specific app
############################################################
resource "kubernetes_network_policy_v1" "app_allow_egress" {
metadata {
name = "allow-app-egress"
namespace = "TARGET_NAMESPACE"
}
spec {
pod_selector {
match_labels = {
app = "APP_LABEL" # same label as above
}
}
egress {
to {
ip_block {
cidr = "ALLOWED_DEST_CIDR" # e.g. "10.0.0.0/16" or specific service CIDR
}
}
ports {
port = 443
protocol = "TCP"
}
}
policy_types = ["Egress"]
}
}
This finding cannot be fixed directly on the oci_containerengine_cluster (OKE cluster) resource: Oracle’s Terraform provider does not expose Kubernetes NetworkPolicy there. Network policies must be applied as Kubernetes resources using the kubernetes_network_policy_v1 resource against the OKE API as shown.
No resource replacement of the OKE cluster is required; only in-cluster policy objects are added/updated. terraform plan should show + (create) or ~ (update) for the kubernetes_network_policy_v1 resources and no changes to oci_containerengine_cluster.