With the new release of the Cilium CNI on our Kubernetes Service you’ll get the ability to filter traffic based on L7 properties. It’s very powerful and can help a lot with your services security.
In this tutorial, we’ll be securing an API endpoint to allow access only to specific routes by our client. All other traffic won’t even be forwarded to the service, thus keeping the load of the API as low as possible.
Prerequisites
Before you get started, you’ll need the following:
- A Kubernetes cluster up and running with Cilium.
kubectl
command-line tool installed and configured to communicate with your cluster.- Basic knowledge of Kubernetes pods, services, and namespaces.
Creating API + API-Client
$ kubectl apply -f https://gist.github.com/modzilla99/0cbdd39cc838e752ae8cdb5ec3cdd03a/raw/adb7218bb1e9195c42192d71809f6f7043e50cd7/deploy.yaml configmap/apiconfig created deployment.apps/api created service/api created pod/api-client created
We’ve now created a service called “api” that is bound to the “api” deployment. It has two routes. The route /secret should be private and /greetings should be publicly accessible. Since we don’t have any NetworkPolcies defined, both routes are accessible by any pod running in the cluster.
Testing the API
So let’s try out the API first:
$ kubectl exec -it api-client -- curl -H 'X-Security-Header: mysecret' api/secret/mysecret { "name": "mysecret", "secret": "syferghewg" } $ kubectl exec -it api-client -- curl api/greetings/World Greetings, World! $ kubectl exec -it api-client -- curl google.com The document has moved
As you can see the API is fully accessible without any restrictions and the api-client pod has full access to the web.
Limiting Access
In order to minimize access, we aim to restrict the pods access exclusively to our api and api.github.com. The subsequent NetworkPolicy will effectively accomplish this goal:
--- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: allow-client-egress spec: endpointSelector: # Apply policy to api client matchLabels: app: client type: production ingress: # Drop all incoming traffic - {} egress: # Allow API acccess to GitHub only via HTTPs - toFQDNs: - matchName: api.github.com toPorts: - ports: - port: "443" # Allow access to our API - toEndpoints: - matchLabels: app: api type: production toPorts: - ports: - port: "6090" protocol: TCP # Allow DNS queries - toEndpoints: - matchLabels: io.kubernetes.pod.namespace: kube-system k8s-app: kube-dns toPorts: - ports: - port: "53" rules: dns: - matchPattern: "*"
Now the pod can only talk to our and the GitHub API as well as query the kubernetes DNS server. Any request to other resources will fail now:
$ kubectl exec -it api-client -- curl -4 --connect-timeout 3 -v google.com * processing: google.com * Trying 142.250.184.238:80... * ipv4 connect timeout after 2974ms, move on! * Failed to connect to google.com port 80 after 3001 ms: Timeout was reached * Closing connection curl: (28) Failed to connect to google.com port 80 after 3001 ms: Timeout was reached $ kubectl exec -it api-client -- curl -4 https://api.github.com/user { "message": "Requires authentication", "documentation_url": "https://docs.github.com/rest/users/users#get-the-authenticated-user" }
Let’s secure secure our api next. We don’t want the pod to able to communicate externally and it should only allow ingress traffic to our two routes. Since the /greetings Endpoint is supposed to be public, we’ll open the access to anyone whilst restricting the access to the /secret Route to our api-client.
--- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy metadata: name: allow-api-ingress spec: endpointSelector: matchLabels: app: api type: production egress: # Deny any external traffic - {} ingress: # Allow access to /secret route from our api client - fromEndpoints: - matchLabels: app: client type: production toPorts: - ports: - port: "6090" protocol: TCP rules: http: - method: "GET" path: "/secret/.*" # Require HTTP header for authorization headers: - 'X-Security-Header: mysecret' # Allow access to /greetings route from anyone - toPorts: - ports: - port: "6090" protocol: TCP rules: http: - method: "GET" path: "/greetings/.*"
Now we can only access the /secret route with the required header and from the api-client pod:
$ kubectl exec -it api-client -- curl api/secret/mysecret Access denied $ kubectl exec -it api-client -- curl -H 'X-Security-Header: mysecret' api/secret/mysecret { "name": "mysecret", "secret": "adasge53whbetn" }
Conclusion
Cilium NetworkPolicies are a powerful way to control network traffic within your cluster. By defining rules for ingress and egress traffic, you can secure your applications and isolate them as needed. This tutorial covered the basics of creating and using NetworkPolicies, but you can create more complex policies to suit your specific needs.
Need help with this topic? Feel free to send us a message or subscribe to our newsletter for more content on the topic.