As more organizations adopt Kubernetes to manage their containerized workloads, securing Kubernetes clusters has become a top priority. While Role-Based Access Control (RBAC) and Pod Security Policies (PSP) are essential components of Kubernetes security, they are not enough to provide comprehensive protection against threats. Let’s explore advanced techniques for securing Kubernetes beyond RBAC and PSP.

Network Policies

Network policies are a powerful feature of Kubernetes that provides fine-grained control over network traffic between pods. By default, all pods in a Kubernetes cluster can communicate with each other, which can create security risks. Network policies allow you to define rules that restrict network traffic based on labels, IP addresses, and ports.

Here's an example of a network policy that allows traffic only between pods with the label "app: my-app" and denies all other traffic:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
 name: allow-my-app
spec:
 podSelector:
   matchLabels:
     app: my-app
 policyTypes:
 - Ingress
 ingress:
 - from:
   - podSelector:
       matchLabels:
         app: my-app
   ports:
   - protocol: TCP
     port: 80

This network policy uses the "podSelector" field to select pods with the label "app: my-app" and allows incoming traffic only from those pods on port 80.

Admission Controllers

Admission controllers are plugins that intercept requests to the Kubernetes API server and enforce policies before allowing or denying the request. Admission controllers can be used to enforce a wide range of policies, including resource quotas, image validation, and pod security policies.

Here's an example of an admission controller that enforces a policy that requires all containers to run as a non-root user:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
 name: run-as-non-root
Webhooks:
- admissionReviewVersions:
  - v1
  name: run-as-non-root.example.com
  rules:
  - apiGroups: [“”]
    apiVersions: [“v1”]
    operations: [“CREATE”]
    resources: [“pods”]
    failurePolicy: Fail
    clientConfig:
	service:
	  name: run-as-non-root-webhook
	  namespace: kube-system
	  Path: “/mutate”
     caBundle: ${CA_BUNDLE}
  sideEffects: None

This admission controller uses a mutating webhook to modify the pod specification and set the "runAsUser" field to a non-root user. The "failurePolicy" field is set to "Fail" to ensure that the pod is not created if the webhook fails.

Security Contexts

Security contexts allow you to define security settings for a pod or container. Security contexts can be used to set privileges, capabilities, and SELinux contexts for containers. 

Here's an example of a security context that sets the "runAsUser" field to 1000 and the "runAsGroup" field to 3000:

apiVersion: v1
kind: Pod
metadata:
 name: my-pod
spec:
  containers:
  - image: ubuntu
    command:
      - "sleep"
      - "604800"
    imagePullPolicy: IfNotPresent
    name: ubuntu
    securityContext:
      runAsUser: 1000
      runAsGroup: 3000
  restartPolicy: Always

This security context sets the "runAsUser" field to 1000 and the "runAsGroup" field to 3000, ensuring that the container runs with the specified user and group IDs.

Pod Security Standards

Pod security standards are a set of guidelines for configuring pod security policies. Pod security standards define a set of baseline requirements for pod security, including requirements for container images, network policies, and security contexts. 

Here's an example of a pod security standard that requires all containers to run as a non-root user and use a read-only root file system:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
 name: restricted
spec:
 privileged: false
 allowPrivilegeEscalation: false
 requiredDropCapabilities:
 - ALL
 allowedCapabilities: []
 volumes:
 - 'configMap'
 - 'emptyDir'
 - 'projected'
 - 'secret'
 - 'downwardAPI'
 runAsUser:
   rule: 'MustRunAsNonRoot'
 fsGroup:
   rule: 'MustRunAs'
   ranges:
   - min: 1
     max: 65535
 seLinux:
   rule: 'RunAsAny'
 supplementalGroups:
   rule: 'MustRunAs'
   ranges:
   - min: 1
     max: 65535
 readOnlyRootFilesystem: true
 hostNetwork: false
 hostPorts: false
 hostPID: false
 hostIpc: false

This pod security standard requires all containers to run as a non-root user, use a read-only root filesystem, and disables privileged mode. It also restricts access to host networking, host ports, host PIDs, and host IPC.

Image Scanning

Container images often contain vulnerabilities that can be exploited by attackers. Image scanning tools can help identify known vulnerabilities in container images and alert you to potential security issues. Kubernetes provides built-in support for image scanning through its Container Runtime Interface (CRI). You can configure CRI to scan images automatically when they are pushed to a registry or manually trigger scans using command-line tools.

Here's an example of how to manually trigger a scan of a container image using Anchore Engine, an open-source image scanning tool:

  1. Install Anchore Engine in your environment.

  2. Create a new analysis: $ anchore-cli image add --name /:

  1. Wait for the analysis to complete.

  2. View the results: $ anchore-cli image analyze /:

 The output will include information about any vulnerabilities found in the image and recommendations for remediation.

Seccomp Profiles

Seccomp profiles limit the syscalls that a container can make, reducing the risk of container breakouts and privilege escalations. Seccomp profiles can be applied to individual containers or entire pods. Kubernetes supports two types of Seccomp profiles: strict and runtime. Strict profiles deny all syscalls except for a whitelist of approved syscalls, while runtime profiles allow all syscalls by default and require explicit denials.

Here's an example of how to apply a Seccomp profile to a container:

Create a Seccomp profile:
{
   "defaultAction": "SCMP_ACT_ERRNO",
   "syscalls": [
       {
           "names": ["open"],
           "action": "SCMP_ACT_ALLOW",
           "args": []
       },
       // Add more syscall rules here
   ]
}
Save the profile to a file, such as my-profile.json.
Apply the profile to a container:
apiVersion: v1
kind: Pod
metadata:
 name: audit-pod
 labels:
   app: audit-pod
spec:
 securityContext:
   seccompProfile:
     type: Localhost
     localhostProfile: /path/to/my-profile.json
 containers:
 - name: test-container
   image: hashicorp/http-echo:1.0
   args:
   - "-text=just made some syscalls!"
   securityContext:
     allowPrivilegeEscalation: false

This security context applies the Seccomp profile specified in my-profile.json to the container.

Secrets Management

Another critical aspect of securing Kubernetes clusters is secrets management. Secrets such as passwords, tokens, and certificates must be stored securely and accessed only by authorized components. Kubernetes provides several ways to manage secrets, including storing them as environment variables, config maps, or secret objects. Secret objects are recommended because they provide encryption at rest and in transit, access control, and fine-grained permissions. 

Here's an example of creating a secret object containing a database password:

kubectl create secret generic db-secret --from-literal=password=mysecretpassword

Once created, secrets can be mounted as files within pods or accessed directly via environment variables. Access control can be implemented using RBAC rules, denying access to unauthorized users.

Runtime Security

Finally, runtime security is essential for detecting and preventing attacks against your cluster. Runtime security tools such as container runtimes, Kubernetes admission controllers, and service meshes can monitor and enforce policies at runtime. Container runtimes such as Docker, containerd, and cri-o provide runtime isolation, resource limits, and network policies for each container. They can also detect and prevent attacks such as container escapes, privilege escalations, and malicious processes. Here's an example of setting up runtime security using Docker:

yaml{
   "security": {
       "apparmor": {
           "profile": "unconfined"
       },
       "selinux": {
           "enabled": false
       }
   }
}

We disable SELinux and set AppArmor to unconfined mode, providing maximum flexibility for our containers. However, you may want to restrict these settings further based on your security requirements.

Service meshes 

Service meshes are another option for runtime security. Service meshes provide features such as traffic management, observability, and security for microservices architectures. Service meshes typically operate at the network layer, injecting proxies into each pod to manage traffic flow and enforce security policies. 

Here's an example of setting up a service mesh using Istio:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: myservice
spec:
 hosts:
   - myservice.default.svc.cluster.local
 http:
   - match:
       - headers:
           host:
             exact: myservice.example.com
     route:
       - destination:
           host: myservice.default.svc.cluster.local
           port:
             number: 80
         weight: 100

We define a virtual service called myservice that routes incoming requests to our backend service based on HTTP headers. We specify the hostname of our frontend service and the backend service to route requests to.Conclusion:Securing Kubernetes clusters requires advanced techniques beyond RBAC and Pod Security Policies. Network security, secrets management, and runtime security are critical aspects of securing Kubernetes clusters. Using network policies, secret objects, container runtimes, admission controllers, and service meshes, you can enforce fine-grained policies, detect and prevent attacks, and monitor your cluster's health.

Conclusion

Securing Kubernetes clusters requires a multi-layered approach that goes beyond RBAC and Pod Security Policies. Network policies, admission controllers, security contexts, pod security standards, image scanning, and Seccomp profiles are advanced techniques that can help you secure your Kubernetes clusters and protect against threats. By implementing these techniques, you can ensure that your Kubernetes clusters are secure and compliant with industry best practices. 

Remember: Security is an ongoing process. Regularly review and update your security practices to adapt to evolving threats and maintain a robust security posture for your Kubernetes deployments.