CCA — Cilium Certified Associate
Why can adding a policy open more doors?
In one line
Creating more policy files does not make communication safer. You have to check which Pods are restricted in which direction, how multiple allow rules combine, and whether the separate communication needed for name resolution is still there. This module uses real requests and Cilium observation records to tell apart two outages that occurred after security work.
Why this was needed
The blue team manages an internal order API. When the security officer asked them to reduce outbound connections, the team restricted the client's egress to port 8080 of the API. The policy was applied successfully and the API Pod was Ready. But in the application, orders stopped. A direct request to the API Pod's IP gets a response, but a request by Service name waits and ends.
At first they assumed an API failure and restarted the server. But changing the server gave the same result. The control group matters here. Going from the same source to the same port of the same server, changing only the path that resolves the address made the results diverge. Instead of changing several settings at once, you should first ask which dependency this difference reveals.
Another team added an allow policy to open the API to a partner organization. Since the existing policy was still there, they thought the new policy was an additional screening condition. But two allow policies can be two doors. The requirement was written as an AND, but the implementation was made as an OR. A security review is not about the number of files but about checking who can pass through which door.
How it works
1. Separate the intent the API expresses from the enforcer
The basic Kubernetes NetworkPolicy also supports podSelector and namespaceSelector. It is not a policy that only lists IP addresses. The policy's top-level podSelector selects the target to protect, from in ingress selects the incoming peers, and to in egress selects the outgoing peers. Putting a namespaceSelector and a podSelector in the same peer means a peer that matches both conditions, while splitting them into separate list items makes them different allow paths.
What actually controls packets is the network plugin that supports policies. In this lab, Cilium handles both the standard NetworkPolicy and the CiliumNetworkPolicy. So do not look only at the fact that the API object was stored; also check the selected endpoints and the results of real requests. Compare the detailed meaning of selectors with the official Kubernetes explanation.
2. Clients with the same name do not have the same identity
A Cilium identity corresponds to a set of security-relevant labels. Even if both the blue team's client and the red team's client have role=client, their namespace-related labels differ. Do not just memorize the numeric ID or compare only the app label. You have to read the CEP's identity.id and identity.labels side by side to check which set is being distinguished. Nor should you store this number like a permanent customer number for an application. The Cilium terminology explanation is the starting point.
A CNP's endpointSelector selects targets in the namespace the policy belongs to. To allow a source in another namespace, you must express that boundary explicitly. This module uses namespaced CNPs registered in Kubernetes. It does not generalize to the same scope for objects put directly into the policy API or for cluster-wide policies. Read the namespace boundary guide alongside.
3. Blocking ingress is different from blocking egress
The policyEnforcementMode in this environment is default. You have to distinguish a direction that no policy selects from a direction that a restricting rule selects. Narrowing the server's ingress does not automatically bring the client's egress to the same scope. Conversely, allowing traffic out to the API does not mean you also allowed traffic out to the name resolution server.
This lab leaves behind separately a client that allows only API 8080 and a client that also allows DNS. For the former, name requests fail while the success of direct IP requests is maintained, and for the latter both requests must succeed. To restore DNS, you specify the kube-dns endpoint in kube-system and UDP/TCP 53. Opening all egress to make the error go away is outside the scope of the task. Besides default there are also always and never, and exceptions for enableDefaultDeny and L7, so do not apply the phenomenon seen here as is to every setting. Check the conditions in policy enforcement modes.
4. Distinguish the union of allows from an explicit deny
The union server has a CNP that allows the blue team's client. If you add a standard NetworkPolicy that allows the red team's client to this, you can create a state in which both teams get through. Do not read the new policy as a filter that narrows the existing allow further. Lay out all the allow paths applied to the same Pod.
For the deny server, you keep allow paths like the above and add a CNP that explicitly denies the red team. Cilium's explicit deny takes precedence over allows, including the standard NetworkPolicy. This is a different concept from default-deny, where traffic is blocked simply because there is no allow rule. Do not over-extend this feature to mean that you can deny a particular URL or FQDN. See the precedence and limits of explicit deny.
| Target | Blue client | Blue stranger | Red client | Reason for comparison |
|---|---|---|---|---|
| baseline | Allowed | Allowed | Allowed | A control where the server itself responds |
| native | Allowed | Denied | Denied | The standard NP's same-namespace selection |
| ingress | Allowed | Denied | Denied | The CNP's source selection |
| union | Allowed | Denied | Allowed | The union of allows from different APIs |
| deny | Allowed | Denied | Denied | A deny that takes precedence over the red team's allow |
This table is the target state of the isolation lab you will set up next. It does not mean that all the correct policies are already applied from the initial state. You read the actual policies and send requests to narrow down the cells that differ from the target.
What it looks like in the field
HTTP 000 is not a status code sent by a server. It also appears when curl could not obtain an HTTP response code. Do not conclude that it is due to network policy just because of a timeout. A server that is not running, a wrong address, and connection path problems can look the same. So look together at the server being Ready, the direct-IP control, the client's location, the policy spec, and the Hubble verdicts.
Finding a single DROPPED line in Hubble is not enough. The observation buffer also contains requests from earlier experiments and other Pods. Matching the source Pod and namespace, IP, destination port, unique source port, and the time narrows the scope of the investigation. Comparing the CEP identity as well reduces the risk of confusing different endpoints with the same name. Also distinguish the fact that a TCP SYN was forwarded from the fact that an HTTP 200 was received. The former is an observation of the forwarding path, and the latter is an application response.
Narrow the scope yourself using the filters in the Hubble CLI guide.
In the real preliminary probe, among 22 requests, the one request that stopped at DNS resolution had no TCP flow. If you judged this to be a missing TCP log, the observer would be wrong, because that request stopped at a stage before connecting to the API. You have to look together at the UDP 53 drop of DNS and the success of the direct-IP request. The DNS evidence at that time was a comparison of time windows and the sending Pod, not packet proof linked down to the query ID. Stating the scope of your evidence is also part of an incident report.
What you will do in the next lab
In a prepared isolated VM, you first check the identities and the control. Then you set up the selectors of the standard NP and the CNP, an egress without DNS and a restored egress, and the union of allows and deny precedence on different targets. Even after a step ends, keep the earlier comparison targets. At the end, you write an incident report that compares the policies with the observation results.
The union and baseline that this lab deliberately leaves open are isolated targets for comparison. Do not copy them as they are into a production environment. To keep your work, you must export it before ending the session. The experiments in this module are about Cilium policy behavior inside a single VM, and do not verify multi-cluster connections, BGP routing, or L7 URL restrictions.