Isovalent Networking for Kubernetes enhances Red Hat OpenShift by providing consistent networking, observability, and security for your OpenShift cluster. This gives administrators ultimate control of their enterprise Kubernetes platform across their environments by delivering granular application metrics and insights into the behavior of their applications across multiple clusters and cloud environments.
Did you know that when someone creates a new OpenShift Project, it is immediately usable but does not include network isolation by default? This design choice simplifies self service for developers, while enterprise environments often need to refine it to meet organizational security and multi-tenancy requirements.
In this blog post we explore how to lock down Namespaces created by Projects while still keeping the rich self-service capabilities of OpenShift.
We will cover how you can set up OpenShift to automatically create a CiliumNetworkPolicy when an OpenShift user creates a Project. This will demonstrate the use case of isolating a Kubernetes Namespace anytime one is created via a Project request.
What is an OpenShift Project?
An OpenShift Project is a Kubernetes Namespace enhanced with additional metadata, role bindings, and policies that OpenShift uses to manage access and resource governance. It serves as the primary interface through which users interact with cluster resources, providing a consistent framework for controlling who can create, modify, or view workloads within a given scope.
For example, when a user creates a Project in OpenShift, a corresponding Kubernetes Namespace is automatically created along with default role bindings, quotas, and security settings. This ensures the user can immediately deploy applications while keeping their Kubernetes objects isolated and inaccessible to other tenants. As a result, teams receive a ready-to-use, secure workspace without requiring cluster-admin intervention.
But what if other configurations are required beyond the default Project implementation?
OpenShift administrators can further expand what a Project does at creation, including applying a CiliumNetworkPolicy to the Namespace that gets created.
Isolating Namespaces
One of the most common use cases for Kubernetes network isolation via Namespaces is creating a network boundary that keeps applications in one namespace isolated from traffic coming from other namespaces. This approach is especially important in multitenant Kubernetes clusters, where multiple teams or workloads share the same infrastructure and by default are not stopped from accessing each other.
We can achieve this easily with CiliumNetworkPolicies, which allow us to block ingress traffic from outside a given namespace. For example:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "isolate-mynamespace"
namespace: mynamespace
spec:
endpointSelector:
matchLabels:
{}
ingress:
- fromEndpoints:
- matchLabels:
{}The above policy blocks all ingress traffic to workloads running in the specified namespace but it allows egress traffic from that specified namespace. This is a great starting point for systems running in a multitenant environment. But how can we ensure that every tenant gets this basic isolation policy automatically?
This is where OpenShift Project creation comes in!
Extending OpenShift Project Creation
OpenShift provides a built-in Project creation template that we can customize. That way, we can ensure every new namespace gets a basic network isolation policy. By extending this template, we can automatically include additional resources, and in this case it’ll be a baseline CiliumNetworkPolicy, so that every new Project is preconfigured with the necessary network isolation.
With administrator privileges, generate the default Project template:
oc adm create-bootstrap-project-template -o yaml > my-template.yamlThe resulting template should look something like this:
apiVersion: template.openshift.io/v1
kind: Template
metadata:
creationTimestamp: null
name: project-request
objects:
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: ${PROJECT_DESCRIPTION}
openshift.io/display-name: ${PROJECT_DISPLAYNAME}
openshift.io/requester: ${PROJECT_REQUESTING_USER}
creationTimestamp: null
name: ${PROJECT_NAME}
spec: {}
status: {}
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: admin
namespace: ${PROJECT_NAME}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: ${PROJECT_ADMIN_USER}
parameters:
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_DESCRIPTION
- name: PROJECT_ADMIN_USER
- name: PROJECT_REQUESTING_USERThere are just a couple of things to note here:
- The Project request template is just an array of objects that gets created when someone creates a project.
- The
parameterssection are the things that are passed during the creation of the Project by the user. Either via theoc new-projectcommand or via the OpenShift web console.
We are going to extend this by adding the CiliumNetworkPolicy to the Project creation template, taking note to add the parameters where it makes sense. The updated Project creation template should look something like this after edited:
apiVersion: template.openshift.io/v1
kind: Template
metadata:
creationTimestamp: null
name: project-request
objects:
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: ${PROJECT_DESCRIPTION}
openshift.io/display-name: ${PROJECT_DISPLAYNAME}
openshift.io/requester: ${PROJECT_REQUESTING_USER}
creationTimestamp: null
name: ${PROJECT_NAME}
spec: {}
status: {}
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: admin
namespace: ${PROJECT_NAME}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: ${PROJECT_ADMIN_USER}
- apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "${PROJECT_NAME}-cnp"
namespace: "${PROJECT_NAME}"
spec:
endpointSelector:
matchLabels:
{}
ingress:
- fromEndpoints:
- matchLabels:
{}
parameters:
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_DESCRIPTION
- name: PROJECT_ADMIN_USER
- name: PROJECT_REQUESTING_USEROnce the Project template is edited, it needs to be applied to the openshift-config namespace, taking note that the name of the Project template is called project-request by default:
oc create -f my-template.yaml -n openshift-configOnce the updated Project template has been applied to the cluster, the project configuration resource needs to be updated. This is done by updating the spec section to include the projectRequestTemplate section with the name: project-request parameter:
oc patch project.config.openshift.io/cluster \
--type='merge' -p '{"spec":{"projectRequestTemplate":{"name":"project-request"}}}'Verify that the OpenShift Project configuration has been updated:
oc get project.config.openshift.io/cluster -o yaml | yq .specThis should output the following:
projectRequestTemplate:
name: project-requestTesting Project Creation
Create a new OpenShift Project by running the oc new-project command:
oc new-project my-isolated-projectThe new project is created and if you run oc get ciliumnetworkpolicy -n my-isolated-project you should see that the CiliumNetworkPolicy was created along with the other objects:
NAME AGE VALID
my-isolated-project-cnp 55s TrueInspect the YAML with the following command:
oc get cnp my-isolated-project-cnp -n my-isolated-project -o yaml | yq .specYou will see the CiliumNetworkPolicy was created on the corresponding Kubernetes namespace:
endpointSelector:
matchLabels: {}
ingress:
- fromEndpoints:
- matchLabels: {}Let’s test this! Let’s deploy a sample application:
oc new-app --name myapp --image quay.io/christianh814/webtest:latestLet’s try to access this application from outside the namespace (in my case I had a pod called tmp-client in a namespace called demo):
kubectl -n demo exec -it \
tmp-client -- curl --fail-early --max-time 2 -I myapp.my-isolated-project.svc:8080The output will show:
curl: (28) Connection timed out after 2002 milliseconds
command terminated with exit code 28With this set up, every time a user creates a Project it will include a CiliumNetworkPolicy that blocks ingress traffic that comes from outside the namespace that was created.
With this set up, anytime a user creates a Project it will automatically include a baseline CiliumNetworkPolicy, blocking ingress network traffic to the respective namespace. This ensures workloads in newly created namespaces are isolated from traffic from other namespaces and provides consistent network security in a multitenant environment.
Ready to Dive Deeper?
CiliumNetworkPolicies go beyond standard Kubernetes NetworkPolicies by leveraging eBPF for high-performance, kernel-level enforcement. They support more advanced features such as identity-based security, L7 (application-layer) policies, and dynamic service-aware rules.
This allows finer-grained control, better scalability, and enhanced observability for securing complex, multitenant environments. Paired together with OpenShift’s rich self-service capabilities and application toolset; Isovalent Networking for Kubernetes strengthens OpenShift by giving Application Developers and Site Reliability Engineers the needed tools for granular application metrics and deep insight into the behavior of their applications.
Want to take your OpenShift platform to the next level? Take a look at our hands-on lab Isovalent Enterprise for Cilium: Network Policies, where you’ll get a more in depth look at CiliumNetworkPolices.
Be sure to also check out our free eBook “Kubernetes Network Policies Done the Right Way”. This practical guide covers Zero Trust, effective network policy design, and tools like Cilium and Hubble to help you protect and optimize your infrastructure.
Safely Managing Cilium Network Policies in Kubernetes
Network policy changes are among the most frequent operations in a Kubernetes cluster. They are also among the most delicate, as even a small mistake can lead to widespread traffic disruption.
This tutorial walks through several methods to make policy management safer, especially in day-2 operations or brownfield deployments where clusters already run critical workloads.
Christian Hernandez, Technical Marketing Engineer