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
Remediation
Using Console
In OKE, namespaces are Kubernetes objects, so you remediate this by:
-
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.
-
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
kubectlsetup command shown (something likeoci ce cluster create-kubeconfig ...). - Paste that command into Cloud Shell and run it.
- Verify access:
kubectl get ns
-
Create a Non-Default Namespace
- Still in Cloud Shell, create a new namespace, e.g.
prod:kubectl create namespace prodkubectl get ns - Confirm
prod(or your chosen name) appears.
- Still in Cloud Shell, create a new namespace, e.g.
-
Move Workloads Out of
defaultNamespace For each deployment/service currently indefault:-
Export its manifest:
kubectl get deploy <deployment-name> -n default -o yaml > deploy.yamlkubectl get svc <service-name> -n default -o yaml > svc.yaml -
Edit the YAML files (in Cloud Shell, use
nanoorvi):- Change:
to:namespace: defaultnamespace: prod
- Remove fields under
metadatathat Kubernetes auto-manages (likeuid,resourceVersion,creationTimestamp,managedFields) to avoid errors.
- Change:
-
Apply them into the new namespace:
kubectl apply -f deploy.yamlkubectl apply -f svc.yaml -
Once confirmed running in the new namespace, delete from
default:kubectl delete deploy <deployment-name> -n defaultkubectl delete svc <service-name> -n default
-
-
Set a Default Namespace in Your Context (Optional)
- To avoid accidentally using
default:kubectl config set-context --current --namespace=prod - Now running
kubectl get podswill act inprodby default.
- To avoid accidentally using
-
Verify No Workloads Use
default- Check
defaultnamespace is empty of your apps:kubectl get all -n default - Only Kubernetes system objects (if any) should remain, or it can be empty.
- Check
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)
- Make sure OCI CLI is configured:
oci setup config
- 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.
- 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
- 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:
- Export current manifests:
kubectl get deploy,svc,ingress,cm,secret -n default -o yaml > default-resources.yaml
-
Edit the file:
- Change
namespace: defaultto the target namespace (e.g.,namespace: prod) undermetadata. - Remove
statussections, and any cluster-assigned fields likeresourceVersion,uid,creationTimestamp, etc.
- Change
-
Apply to new namespace:
kubectl apply -f default-resources.yaml
- 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. Enforce “no workloads in default namespace” (optional but recommended)
4.1 Use a Namespace-level or cluster policy (Gatekeeper / OPA or admission webhook)
If using Gatekeeper (as an example):
- Install Gatekeeper (once per cluster).
- Create a ConstraintTemplate that denies
defaultnamespace usage. - 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
- Ensure no resources exist in
default:
kubectl get all -n default
kubectl get configmap,secret,ingress,serviceaccount -n default
- Ensure workloads run in non-default namespaces:
kubectl get all -n prod
kubectl get all -n staging
kubectl get all -n dev
- Test that new deployments to
defaultare rejected (if you added an admission policy).
Using Python
To remediate “OCI OKE should use non-default namespaces” with Python, you essentially need to:
- Create one or more custom namespaces.
- Migrate workloads from
defaultto the new namespace(s). - 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
-
Ensure you have
kubectlaccess to the OKE cluster and a validkubeconfig:kubectl get nodes -
Install the Kubernetes Python client:
pip install kubernetes -
Ensure your
KUBECONFIGenvironment variable is set (or~/.kube/configexists 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
defaultusage.
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
- Use Python/Kubernetes client to create a non-default namespace in OKE.
- Migrate workloads from
defaultto that namespace (re-create in the new namespace and delete the old). - Change your kubeconfig context so the new namespace is the default.
- 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.