RAPID CYBER AI
WEEK 4 OF 8
0 steps completed
WEEK 4

Kubernetes Security

Lock down clusters from RBAC to runtime detection

10-12 hours

Lab 1: RBAC & Service Accounts

~90 min

Create a local cluster with kind

kind runs Kubernetes inside Docker. Perfect for security labs without cloud costs.

Cluster
$ kind create cluster --name bootcamp
$ kubectl cluster-info --context kind-bootcamp
$ kubectl get nodes

Create scoped RBAC

Scoped role that only allows reading pods and services in one namespace.

RBAC
$ kubectl create namespace bootcamp-app

$ cat > role.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: bootcamp-app
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods", "services"]
  verbs: ["get", "list", "watch"]
EOF

$ kubectl apply -f role.yaml

$ cat > binding.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: bootcamp-app
  name: read-pods
subjects:
- kind: ServiceAccount
  name: app-reader
  namespace: bootcamp-app
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
EOF

$ kubectl apply -f binding.yaml

Test access controls

The service account can read pods in its namespace but nothing else.

Verify RBAC
# Check what the service account can do:
$ kubectl auth can-i list pods --namespace bootcamp-app --as system:serviceaccount:bootcamp-app:app-reader
# yes

$ kubectl auth can-i create pods --namespace bootcamp-app --as system:serviceaccount:bootcamp-app:app-reader
# no

$ kubectl auth can-i list pods --namespace kube-system --as system:serviceaccount:bootcamp-app:app-reader
# no

Lab 2: Network Policies

~90 min

Install Calico CNI

Default kind CNI doesn't support NetworkPolicies. Calico does.

Calico
# Delete existing cluster and recreate with Calico
$ kind delete cluster --name bootcamp
$ cat > kind-config.yaml << 'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: true
  podSubnet: "192.168.0.0/16"
EOF

$ kind create cluster --name bootcamp --config kind-config.yaml
$ kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
$ kubectl wait --for=condition=Ready nodes --all --timeout=120s

Apply default-deny

Blocks all traffic. Now nothing communicates — we selectively open what's needed.

Default deny
$ cat > default-deny.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: bootcamp-app
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF

$ kubectl apply -f default-deny.yaml
WHY THIS MATTERS

By default, every pod can talk to every other pod. One compromised pod reaches your database, your secrets, your monitoring. Default-deny fixes this.

Allow frontend→backend traffic

Backend only accepts traffic from frontend pods on port 8080. Everything else is blocked.

Allow policy
$ cat > allow-frontend.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: bootcamp-app
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
EOF

$ kubectl apply -f allow-frontend.yaml

Lab 3: Pod Security Standards

~60 min

Apply restricted profile

Restricted profile prevents root containers, privileged mode, hostPath mounts, and more.

PSS
$ kubectl label namespace bootcamp-app \
    pod-security.kubernetes.io/enforce=restricted \
    pod-security.kubernetes.io/warn=restricted \
    pod-security.kubernetes.io/audit=restricted

# Try deploying a privileged pod (should be rejected):
$ kubectl run test-priv --image=nginx --namespace bootcamp-app \
    --overrides='{"spec":{"containers":[{"name":"test","image":"nginx","securityContext":{"privileged":true}}]}}'
# Error: violates PodSecurity "restricted"

Deploy a compliant pod

Non-root, read-only filesystem, dropped capabilities, resource limits, seccomp profile.

Compliant pod
$ cat > secure-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: bootcamp-app
  labels:
    app: backend
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:alpine
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      readOnlyRootFilesystem: true
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 256Mi
EOF

$ kubectl apply -f secure-pod.yaml

Lab 4: OPA Gatekeeper

~60 min

Install Gatekeeper

Gatekeeper enforces custom policies at admission time.

Install
$ helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
$ helm install gatekeeper gatekeeper/gatekeeper \
    --namespace gatekeeper-system --create-namespace

$ kubectl wait --for=condition=Ready pods -l app=gatekeeper -n gatekeeper-system --timeout=120s

Create a registry restriction policy

Only images from your approved registry are allowed to deploy.

Policy
$ cat > registry-constraint-template.yaml << 'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sallowedrepos
spec:
  crd:
    spec:
      names:
        kind: K8sAllowedRepos
      validation:
        openAPIV3Schema:
          type: object
          properties:
            repos:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sallowedrepos
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not startswith(container.image, input.parameters.repos[_])
          msg := sprintf("image '%v' not from allowed registry", [container.image])
        }
EOF

$ kubectl apply -f registry-constraint-template.yaml

Lab 5: Runtime Detection with Falco

~60 min

Install Falco

Falco monitors system calls in real-time and alerts on suspicious container activity.

Falco
$ helm repo add falcosecurity https://falcosecurity.github.io/charts
$ helm install falco falcosecurity/falco \
    --namespace falco --create-namespace \
    --set falcosidekick.enabled=true

$ kubectl wait --for=condition=Ready pods -l app.kubernetes.io/name=falco -n falco --timeout=120s

Trigger and view detections

Falco detects shell spawning, file writes to sensitive dirs, unexpected network connections, and more.

Test detection
# Exec into a pod (Falco should alert)
$ kubectl exec -it secure-app -n bootcamp-app -- sh

# Check Falco logs for the detection:
$ kubectl logs -l app.kubernetes.io/name=falco -n falco --tail=20 | grep -i "shell"

# You should see:
# Notice: A shell was spawned in a container

Week 4 cleanup

Delete the kind cluster. Zero cloud costs for this week.

Cleanup
$ kind delete cluster --name bootcamp
# All resources are removed with the cluster