Skip to main content

OCI OKE Should Use Non-Default Namespaces

More Info:

Workloads should live in dedicated namespaces, not the default namespace. Per-team namespaces enable namespace-scoped RBAC, NetworkPolicy, and quota, all of which are awkward to apply to default.

Risk Level

Low

Address

Compliance, Security

Compliance Standards

  • CIS OKE

Triage and Remediation

Remediation

Using Console

In OKE, namespaces are Kubernetes objects, so you remediate this by:

  1. Open OCI Console and Cloud Shell

    • Sign in to OCI Console.
    • In the top-right, click Cloud Shell (terminal icon) to open a shell already authenticated to your tenancy.
  2. Get Cluster Kubeconfig in Cloud Shell

    • In the Console, go to Developer Services → Kubernetes Clusters (OKE).
    • Select your cluster.
    • Click Access Cluster (or Cluster Access), choose Local access (for Cloud Shell it’s treated as local), and copy the kubectl setup command shown (something like oci ce cluster create-kubeconfig ...).
    • Paste that command into Cloud Shell and run it.
    • Verify access:
      kubectl get ns
  3. Create a Non-Default Namespace

    • Still in Cloud Shell, create a new namespace, e.g. prod:
      kubectl create namespace prod
      kubectl get ns
    • Confirm prod (or your chosen name) appears.
  4. Move Workloads Out of default Namespace For each deployment/service currently in default:

    • Export its manifest:

      kubectl get deploy <deployment-name> -n default -o yaml > deploy.yaml
      kubectl get svc <service-name> -n default -o yaml > svc.yaml
    • Edit the YAML files (in Cloud Shell, use nano or vi):

      • Change:
        namespace: default
        to:
        namespace: prod
      • Remove fields under metadata that Kubernetes auto-manages (like uid, resourceVersion, creationTimestamp, managedFields) to avoid errors.
    • Apply them into the new namespace:

      kubectl apply -f deploy.yaml
      kubectl apply -f svc.yaml
    • Once confirmed running in the new namespace, delete from default:

      kubectl delete deploy <deployment-name> -n default
      kubectl delete svc <service-name> -n default
  5. Set a Default Namespace in Your Context (Optional)

    • To avoid accidentally using default:
      kubectl config set-context --current --namespace=prod
    • Now running kubectl get pods will act in prod by default.
  6. Verify No Workloads Use default

    • Check default namespace is empty of your apps:
      kubectl get all -n default
    • Only Kubernetes system objects (if any) should remain, or it can be empty.

This satisfies the “use non-default namespaces” requirement using the OCI Console plus Cloud Shell.

Using CLI

Below are concise, step‑by‑step remediation instructions to ensure your OCI OKE cluster uses non‑default namespaces, using OCI CLI (to get kubeconfig) and kubectl (for Kubernetes objects).


1. Get kubeconfig for the OKE cluster (using OCI CLI)

  1. Make sure OCI CLI is configured:
oci setup config
  1. Get your OKE cluster OCID (if you don’t have it already):
oci ce cluster list \
--compartment-id <COMPARTMENT_OCID> \
--all

Copy the id of the target cluster.

  1. Generate kubeconfig for that cluster:
oci ce cluster create-kubeconfig \
--cluster-id <CLUSTER_OCID> \
--file ~/.kube/oke-config \
--region <REGION> \
--token-version 2.0.0 \
--kube-endpoint PUBLIC_ENDPOINT
  1. Point kubectl to that config:
export KUBECONFIG=~/.kube/oke-config

2. Create non-default namespaces

Decide the logical namespaces (e.g., prod, staging, dev).

kubectl create namespace prod
kubectl create namespace staging
kubectl create namespace dev

Check:

kubectl get namespaces

3. Move workloads out of default namespace

3.1 Identify resources currently in default namespace

kubectl get all -n default
kubectl get configmap,secret,ingress,serviceaccount -n default

3.2 Re-deploy workloads into new namespaces

You cannot “move” namespace of an existing object; you must recreate it:

  1. Export current manifests:
kubectl get deploy,svc,ingress,cm,secret -n default -o yaml > default-resources.yaml
  1. Edit the file:

    • Change namespace: default to the target namespace (e.g., namespace: prod) under metadata.
    • Remove status sections, and any cluster-assigned fields like resourceVersion, uid, creationTimestamp, etc.
  2. Apply to new namespace:

kubectl apply -f default-resources.yaml
  1. Once you verify everything runs correctly in the new namespace(s), delete the resources from default:
kubectl delete all --all -n default
kubectl delete configmap,secret,ingress,serviceaccount --all -n default

4.1 Use a Namespace-level or cluster policy (Gatekeeper / OPA or admission webhook)

If using Gatekeeper (as an example):

  1. Install Gatekeeper (once per cluster).
  2. Create a ConstraintTemplate that denies default namespace usage.
  3. Create a Constraint, e.g.:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyDefaultNamespace
metadata:
name: deny-default-namespace
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod", "Service", "ConfigMap", "Secret"]
- apiGroups: ["apps"]
kinds: ["Deployment", "StatefulSet", "DaemonSet", "ReplicaSet"]
namespaces: ["*"]
parameters: {}

(Template details depend on your Gatekeeper setup; key point: reject manifests with metadata.namespace: default or no namespace.)

4.2 Enforce namespace usage in CI/CD

Update Helm charts/Manifests to always specify a non-default namespace and/or use --namespace <ns> in deployment scripts.


5. Validation

  1. Ensure no resources exist in default:
kubectl get all -n default
kubectl get configmap,secret,ingress,serviceaccount -n default
  1. Ensure workloads run in non-default namespaces:
kubectl get all -n prod
kubectl get all -n staging
kubectl get all -n dev
  1. Test that new deployments to default are rejected (if you added an admission policy).
Using Python

To remediate “OCI OKE should use non-default namespaces” with Python, you essentially need to:

  1. Create one or more custom namespaces.
  2. Migrate workloads from default to the new namespace(s).
  3. Enforce that new workloads don’t get deployed into default.

Below are concise, step‑by‑step instructions using Python and the Kubernetes Python client (works with any OKE cluster once you have kubeconfig).


1. Prereqs

  1. Ensure you have kubectl access to the OKE cluster and a valid kubeconfig:

    kubectl get nodes
  2. Install the Kubernetes Python client:

    pip install kubernetes
  3. Ensure your KUBECONFIG environment variable is set (or ~/.kube/config exists and points to OKE):

    export KUBECONFIG=/path/to/oke-kubeconfig

2. Create a Non-Default Namespace via Python

from kubernetes import client, config

# Load kubeconfig for OKE cluster
config.load_kube_config() # or load_incluster_config() if running inside OKE

v1 = client.CoreV1Api()

namespace_name = "prod-apps" # choose your non-default namespace

# Check if namespace already exists
existing_namespaces = [ns.metadata.name for ns in v1.list_namespace().items]
if namespace_name not in existing_namespaces:
namespace_body = client.V1Namespace(
metadata=client.V1ObjectMeta(
name=namespace_name,
labels={"istio-injection": "enabled"} # example label; optional
)
)
v1.create_namespace(body=namespace_body)
print(f"Namespace '{namespace_name}' created.")
else:
print(f"Namespace '{namespace_name}' already exists.")

3. Migrate Existing Deployments from default to the New Namespace

Kubernetes does not support changing the namespace of an existing object in place. You have to:

  • Fetch the object from default
  • Remove the resourceVersion, uid, etc.
  • Re-create it in the new namespace
  • Delete it from default

Example for Deployments:

from kubernetes import client, config
from copy import deepcopy

config.load_kube_config()
apps_v1 = client.AppsV1Api()

old_ns = "default"
new_ns = "prod-apps"

# 1. Get all deployments in the default namespace
deployments = apps_v1.list_namespaced_deployment(namespace=old_ns).items

for dep in deployments:
name = dep.metadata.name
print(f"Migrating deployment: {name}")

# 2. Clean metadata for re-create
new_dep = deepcopy(dep)
new_dep.metadata.namespace = new_ns
for attr in ["resource_version", "uid", "creation_timestamp", "self_link", "generation"]:
if hasattr(new_dep.metadata, attr):
setattr(new_dep.metadata, attr, None)
if new_dep.status:
new_dep.status = None

# 3. Create in new namespace
apps_v1.create_namespaced_deployment(namespace=new_ns, body=new_dep)

# 4. Delete in old namespace
apps_v1.delete_namespaced_deployment(
name=name,
namespace=old_ns,
body=client.V1DeleteOptions(propagation_policy="Foreground")
)
print(f"Deployment '{name}' moved from '{old_ns}' to '{new_ns}'")

Repeat similarly for Services, ConfigMaps, Secrets, etc., as needed.


4. Ensure New Workloads Use Non-Default Namespace

You can enforce non-default namespaces in several ways. The simplest operational method:

  • Create and use context that defaults to your new namespace.
  • Optionally, use an Admission Controller (e.g., Gatekeeper/Kyverno) to block default usage.

4.1. Default to the New Namespace in kubeconfig (Operational Control)

You can script modification of your kubeconfig with Python (YAML edit) so your context defaults to the non-default namespace:

import yaml
from pathlib import Path

kubeconfig_path = Path("~/.kube/config").expanduser()
with kubeconfig_path.open() as f:
cfg = yaml.safe_load(f)

current_context_name = cfg["current-context"]
for ctx in cfg["contexts"]:
if ctx["name"] == current_context_name:
ctx["context"]["namespace"] = "prod-apps" # your non-default ns
break

with kubeconfig_path.open("w") as f:
yaml.safe_dump(cfg, f)

print(f"Context '{current_context_name}' now defaults to namespace 'prod-apps'")

With this, kubectl apply (and tools using this context) will use prod-apps by default instead of default.


5. (Optional) Block Use of default Namespace with Policy

If you use Gatekeeper/OPA or Kyverno on OKE, you can add a policy to deny resources in default. Example (Kyverno) policy YAML (not Python, but you can apply it via Python using the same client patterns above):

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-default-namespace
spec:
validationFailureAction: enforce
rules:
- name: block-default-namespace
match:
any:
- resources:
namespaces:
- default
kinds:
- Pod
- Deployment
- Service
- StatefulSet
- DaemonSet
validate:
message: "Use a non-default namespace. 'default' is not allowed."
deny: {}

You can create that via Python as a generic CustomObjectsApi call if Kyverno is installed.


Summary of Remediation

  1. Use Python/Kubernetes client to create a non-default namespace in OKE.
  2. Migrate workloads from default to that namespace (re-create in the new namespace and delete the old).
  3. Change your kubeconfig context so the new namespace is the default.
  4. Optionally enforce a policy to block new objects in default.

This satisfies the requirement that OKE “should use non-default namespaces” and provides an automated Python-based approach.

Using Terraform

The oci_containerengine_cluster (OKE cluster) resource cannot manage Kubernetes namespaces; namespaces are runtime Kubernetes objects, not an OCI cluster property, so this finding cannot be fixed on that exact resource type via Terraform.

To remediate with Terraform, you must use the Kubernetes provider against the OKE cluster and create non-default namespaces for your workloads, then move workloads to those namespaces:

# Configure Kubernetes provider for the OKE cluster
provider "kubernetes" {
host = "https://YOUR_OKE_ENDPOINT" # Replace with OKE cluster API endpoint
cluster_ca_certificate = base64decode("BASE64_CA_CERT") # Replace with OKE cluster CA cert
token = "BEARER_TOKEN" # Replace with an auth token
}

# Example dedicated namespaces
resource "kubernetes_namespace_v1" "team_a" {
metadata {
name = "team-a" # Replace with your team/tenant namespace name
}
}

resource "kubernetes_namespace_v1" "team_b" {
metadata {
name = "team-b" # Replace with your team/tenant namespace name
}
}

# Example workload moved out of "default" into team-a namespace
resource "kubernetes_deployment_v1" "team_a_app" {
metadata {
name = "team-a-app"
namespace = kubernetes_namespace_v1.team_a.metadata[0].name
}

spec {
replicas = 2

selector {
match_labels = {
app = "team-a-app"
}
}

template {
metadata {
labels = {
app = "team-a-app"
}
}

spec {
container {
name = "app"
image = "YOUR_IMAGE:TAG" # Replace with your image
}
}
}
}
}

This change does not replace the OKE cluster; it only creates namespaces and re-homes workloads. You must separately update or recreate any existing workloads currently in the default namespace to target the new namespaces.

Verification: terraform plan should show creation of kubernetes_namespace_v1 resources and modifications (or replacements) of Kubernetes workload resources changing metadata.namespace from default to the dedicated namespaces.