TT Lab
Get started
Learn Learning paths Courses

CKS — Kubernetes Security Specialist

Cluster Setup Starting From Default Deny

Continue in TT Lab

Goal

You get the order into your hands: make one namespace default deny and then reopen only the needed paths one at a time, and you write out yourself what to check in the control plane configuration file.

Why it matters

Kubernetes defaults are all open. A Pod with no policy at all can communicate with any Pod in the cluster, and it reaches the node's metadata address as is. So the first move of security design is not adding a rule that blocks something, but blocking everything and restoring only what is needed. If you reverse this order, you can never know "what you missed." Configuration file auditing follows the same idea. Reading one manifest is faster than observing a running process, and you can turn what is missing into a list.

This lab environment has no real data plane, so you can't confirm that a policy really cuts traffic. Grading checks whether the object's spec is written as intended. What the exam demands is also an exact spec.

Steps

  1. Create the namespace cks-net and attach the label tier=restricted.
  2. Create the NetworkPolicy default-deny-all in cks-net. Leave podSelector empty and list both Ingress and Egress in policyTypes, but put no ingress/egress rules at all.
  3. Create the NetworkPolicy allow-dns-egress in cks-net. It targets all Pods, policyTypes is only Egress, and the egress destination is the Pods labeled k8s-app=kube-dns in the namespace labeled kubernetes.io/metadata.name=kube-system, with two ports: UDP 53 and TCP 53.
  4. Create the NetworkPolicy allow-frontend-to-api in cks-net. The target is the app=api Pods, the allowed ingress source is the app=frontend Pods in the same namespace, and the port is TCP 8080.
  5. Create the NetworkPolicy deny-node-metadata in cks-net. It targets all Pods, policyTypes is Egress, and the egress destination is an ipBlock with cidr: 0.0.0.0/0 and except: [169.254.169.254/32].
  6. Create a Secret shop-tls of type kubernetes.io/tls in cks-net. Both tls.crt and tls.key must be non-empty.
  7. Create the Ingress shop in cks-net. The hosts of spec.tls[0] is shop.cks.local, secretName is shop-tls, spec.rules[0].host is also shop.cks.local, and the path / is routed to port 8080 of the Service api.
  8. Write a static Pod manifest that reflects the CIS recommendations in /root/cks-cluster-setup/kube-apiserver.yaml. It must have kind: Pod, the container name kube-apiserver, the command array containing --anonymous-auth=false, --authorization-mode=Node,RBAC, --profiling=false, --audit-log-path=/var/log/kubernetes/audit.log, and --enable-admission-plugins=NodeRestriction,PodSecurity, and no flag starting with --insecure-port at all.

Notes

Create the namespace to isolate

Create the namespace cks-net and attach the label tier=restricted.

Create the namespace and attach the label. Write kubectl label ns after kubectl create ns, or you can create it with a single manifest.

A default policy that blocks all ingress and egress

Create the NetworkPolicy default-deny-all in cks-net. Leave podSelector empty and list both Ingress and Egress in policyTypes, but put no ingress/egress rules at all.

podSelector: {} selects all Pods in the namespace. If you list a direction in policyTypes but leave out the ingress/egress rule list entirely, that direction is entirely denied.

Egress that opens only DNS as an exception

Create the NetworkPolicy allow-dns-egress in cks-net. It targets all Pods, policyTypes is only Egress, and the egress destination is the Pods labeled k8s-app=kube-dns in the namespace labeled kubernetes.io/metadata.name=kube-system, with two ports: UDP 53 and TCP 53.

The kube-dns Pods are in the kube-system namespace and carry the label k8s-app=kube-dns. You can select the namespace by the kubernetes.io/metadata.name label. Port 53 is needed for both UDP and TCP.

Ingress that opens only the needed Pod pair

Create the NetworkPolicy allow-frontend-to-api in cks-net. The target is the app=api Pods, the allowed ingress source is the app=frontend Pods in the same namespace, and the port is TCP 8080.

Select the receiving side with podSelector, and select the sending side with ingress[].from[].podSelector. If you don't list a port, all ports are open.

Carve out the path to node metadata

Create the NetworkPolicy deny-node-metadata in cks-net. It targets all Pods, policyTypes is Egress, and the egress destination is an ipBlock with cidr: 0.0.0.0/0 and except: [169.254.169.254/32].

An ipBlock can have an except list attached to a single cidr, and the range in except must be inside the cidr.

A TLS Secret for Ingress

Create a Secret shop-tls of type kubernetes.io/tls in cks-net. Both tls.crt and tls.key must be non-empty.

A Secret of type kubernetes.io/tls must have both the tls.crt and tls.key keys. You can create a self-signed certificate with openssl, or put base64 values directly into the manifest.

Connect TLS to the Ingress

Create the Ingress shop in cks-net. The hosts of spec.tls[0] is shop.cks.local, secretName is shop-tls, spec.rules[0].host is also shop.cks.local, and the path / is routed to port 8080 of the Service api.

In an Ingress's spec.tls, you write the hosts list paired with a secretName. If the host in spec.rules and spec.tls[].hosts don't match, the certificate isn't attached.

Audit the kube-apiserver manifest

Write a static Pod manifest that reflects the CIS recommendations in /root/cks-cluster-setup/kube-apiserver.yaml. It must have kind: Pod, the container name kube-apiserver, the command array containing --anonymous-auth=false, --authorization-mode=Node,RBAC, --profiling=false, --audit-log-path=/var/log/kubernetes/audit.log, and --enable-admission-plugins=NodeRestriction,PodSecurity, and no flag starting with --insecure-port at all.

A static Pod manifest is kind: Pod, and the flags go in the spec.containers[0].command array. CIS recommends blocking anonymous authentication, Node+RBAC authorization, disabling profiling, and the NodeRestriction admission plugin, and flags for an unauthenticated plaintext port must not be present at all.