Firewalls¶
A firewall protects one service. It names the traffic allowed to reach that service, and everything else headed for it is dropped.
For the same steps in the console, see the console walkthrough.
The first firewall flips the default to deny¶
A new project already has firewalls: it starts closed except for web traffic, see what a new project starts with. There, every firewall you add opens something.
The project of a public subnet, and a project older than those defaults, has none. Until such a project has its first firewall, every service in it accepts anything that can route to it. As soon as one firewall selects a service, that service accepts only what the rules allow.
There is no partial state and no warning: one rule flips the default from allow to deny for the workloads it selects. Write the rule your application actually needs before you create it, and expect everything you did not name to stop working immediately.
Create¶
A firewall is a NetworkPolicy whose pod selector matches the pods behind one service:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-<service>
namespace: <project>
spec:
podSelector:
matchLabels:
app: <service> # (1)!
policyTypes:
- Ingress # (2)!
ingress:
- from:
- namespaceSelector:
matchLabels:
hoolia.eu/tenant: <tenant> # (3)!
ports:
- protocol: TCP
port: 8080 # (4)!
- The pods' own labels, not the service's name. Copy them from the service, or the policy protects nothing - see the warning below.
- Ingress only. Listing
Egresshere as well would deny all outbound traffic from these pods in the same apply, because a policy that names a direction and gives it no rules allows nothing in that direction. - Who may connect: here every project of your tenant. Four choices, in increasing order of exposure - see Who may connect.
- The port the container listens on, which is not always the port the service publishes.
The selector must match the pods, not the service
podSelector selects pods directly - a NetworkPolicy has no concept of a service.
Copy the service's own selector so the two agree:
A selector that matches nothing creates a policy that protects nothing, and looks identical to a working one in any list.
Who may connect¶
The from clause is what decides the reach. Four choices, in increasing order of exposure:
| Reach | from |
|---|---|
| Workloads in the same project | - podSelector: {} |
| Workloads in every project of your tenant | - namespaceSelector: {matchLabels: {hoolia.eu/tenant: <tenant>}} |
| Workloads anywhere on the cluster, other customers' included | - namespaceSelector: {} |
| Any source address at all | - ipBlock: {cidr: 0.0.0.0/0} |
The console form offers the first, the third and the fourth. The tenant reach is YAML only.
Start with the narrowest that lets your application work. Narrow is cheap to widen later; wide is what gets exploited in the meantime. How far an allow rule reaches explains what each boundary contains.
The port is the pod's port¶
port is the port the container listens on, which is not always the port the service
publishes. If the two differ, use the container's.
Only what you name is allowed. A service that also serves health checks or metrics on another port needs a second rule, or those checks start failing the moment this one exists.
Open or close a boundary¶
A new project admits its own
workloads and the other projects of your tenant on every port, and everyone else on the web
ports only. Each case below changes one of those boundaries. Replace the from clause of
the firewall in Create with the one shown.
Your project only¶
A new project already admits its own workloads on every port, through
allow-same-namespace. To keep its workloads reachable from their own project and from no
other project, delete the two firewalls that admit more:
oc delete networkpolicy allow-same-tenant -n <project>
oc delete networkpolicy allow-http-https -n <project>
The other projects of your tenant then no longer reach any workload in this project, and
the web ports no longer accept connections from other projects or from the internet. A
Route keeps working, because allow-from-openshift-ingress still admits the routers, and
the other allow-from- firewalls still admit the platform's own services.
To write the reach explicitly for one service:
Your whole tenant¶
A new project already admits every project of your tenant on every port, through
allow-same-tenant. Find the tenant name in the TENANT column:
If you deleted allow-same-tenant, or the project has none, open one service to your
tenant with:
To close the tenant boundary again, delete that firewall, or allow-same-tenant if it is
the one that admits the traffic:
Only the platform sets the hoolia.eu/tenant label, so this rule admits your own projects
and no other customer's.
The whole world¶
A new project already admits any source on TCP 80, 443, 8080 and 8443, through
allow-http-https. To open another port of one service to every source address:
0.0.0.0/0 also matches the addresses of every other project on the cluster. A source
outside the cluster still needs a path to the workload: a Route, a
load balancer or a public subnet.
To close the web ports to the world:
Anywhere in the cluster includes other customers' projects
namespaceSelector: {} selects every project on a shared cluster, not only your own.
For traffic between your own projects, select the tenant label instead.
List¶
To see what a rule actually does:
To find which policies select a given pod:
then compare those labels against each policy's podSelector. An empty podSelector: {}
selects every pod in the project.
Change¶
Policies can be edited in place, and the change takes effect immediately:
oc patch networkpolicy <name> -n <project> --type=json \
-p '[{"op":"add","path":"/spec/ingress/0/ports/-","value":{"protocol":"TCP","port":9090}}]'
There is no staged rollout and no dry run against live traffic, so a mistake here drops real requests from the moment it is applied. Test from where the service is meant to be reachable straight after any change.
Delete¶
Deleting a rule widens access rather than narrowing it. If it was the only policy selecting those pods, the service goes back to accepting everything that can route to it.
Related¶
- Networking - including the default-deny egress pattern
- Load balancers - publishing a service outside the cluster
- Subnets - isolating workloads at the network level