Skip to main content

Command Palette

Search for a command to run...

Securing Applications in Kubernetes

Published
6 min read
Securing Applications in Kubernetes
B

DevOps and Cloud Engineer

Focused on optimizing the software development lifecycle through seamless integration of development and operations, specializing in designing, implementing, and managing scalable cloud infrastructure with a strong emphasis on automation and collaboration.

Key Skills:

Terraform: Skilled in Infrastructure as Code (IaC) for automating infrastructure deployment and management. Ansible: Proficient in automation tasks, configuration management, and application deployment. AWS: Extensive experience with AWS services like EC2, S3, RDS, and Lambda, designing scalable and cost-effective solutions. Kubernetes: Expert in container orchestration, deploying, scaling, and managing containerized applications. Docker: Proficient in containerization for consistent development, testing, and deployment. Google Cloud Platform: Familiar with GCP services for compute, storage, and machine learning.

Introduction

Providing a secure platform to run workloads is critical for Kubernetes adoption in production environments. While Kubernetes offers numerous security-focused APIs, implementing them effectively requires understanding core principles like least privilege and defense-in-depth.

The principle of least privilege means provisioning only the resources needed for Kubernetes workloads—nothing more. This guide walks through implementing comprehensive security controls across every layer of your Kubernetes infrastructure.

Understanding Security Context: The Foundation

At the core of securing pods is the Security Context—an aggregation of all security-focused fields that can be applied at both pod and container specification levels.

Core Security Controls

Security Context covers:

  • User permissions and access control

  • Read-only root filesystem

  • Privilege escalation controls

  • Seccomp, AppArmor, and SELinux profiles

  • Privileged vs unprivileged execution

Practical Implementation

Here's a comprehensive example of a secured pod:

apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  containers:
  - image: gcr.io/kuar-demo/kuard-amd64:blue
    name: kuard
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      privileged: false
    ports:
    - containerPort: 8080
      name: http
      protocol: TCP

Security Context Field Breakdown

runAsNonRoot: true Ensures the container process doesn't run as root (UID 0). Kubernetes will reject containers that attempt to run as root, significantly reducing the attack surface.

runAsUser: 1000 / runAsGroup: 3000 Explicitly sets user and group IDs instead of relying on container image defaults. This provides predictable, controlled permissions.

fsGroup: 2000 Sets group ownership for mounted volumes. When volumes are mounted, their group ownership changes to 2000 with group write permissions.

allowPrivilegeEscalation: false Prevents processes from gaining more privileges than their parent process, blocking operations like sudo or setuid binaries.

privileged: false Ensures containers run in unprivileged mode, maintaining proper container isolation from the host system.

readOnlyRootFilesystem: true Mounts the container's root filesystem as read-only, preventing malware from modifying system files.

Verification: Testing Your Security Controls

Let's verify these settings work as expected:

# Start a shell in the secured pod
kubectl exec -it kuard -- ash

# Check user and group IDs
id
# Output: uid=1000 gid=3000 groups=2000

# Verify processes run as non-root
ps aux
# All processes show user 1000, not root

# Test read-only filesystem
touch /test-file
# Output: touch: /test-file: Read-only file system

This confirms our security context is properly enforced.

Advanced Security Controls

Enhanced Pod with Multiple Security Layers

apiVersion: v1
kind: Pod
metadata:
  name: amicontained
  annotations:
    container.apparmor.security.beta.kubernetes.io/amicontained: "runtime/default"
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - image: r.j3ss.co/amicontained:v0.4.9
    name: amicontained
    command: ["/bin/sh", "-c", "--"]
    args: ["amicontained"]
    securityContext:
      capabilities:
        add: ["SYS_TIME"]
        drop: ["NET_BIND_SERVICE"]
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      privileged: false

Security Enhancement Breakdown

AppArmor Integration

annotations:
  container.apparmor.security.beta.kubernetes.io/amicontained: "runtime/default"

Applies runtime default AppArmor profile for additional access control.

Seccomp Profile

seccompProfile:
  type: RuntimeDefault

Uses runtime's default seccomp profile, blocking 21+ dangerous system calls.

Linux Capabilities

capabilities:
  add: ["SYS_TIME"]      # Grant specific capabilities
  drop: ["NET_BIND_SERVICE"]  # Remove dangerous capabilities

Pod Security Standards

Kubernetes provides three built-in security levels for systematic policy enforcement:

Security Levels

Baseline 🟡

  • Prevents most privilege escalations

  • Good starting point for most workloads

  • Enables easier onboarding

Restricted 🔴

  • Highly restrictive security best practices

  • May cause some workloads to break

  • Recommended for high-security environments

Privileged 🟢

  • Open and unrestricted

  • Allows dangerous configurations

  • Use only when absolutely necessary

Implementing Pod Security Standards

apiVersion: v1
kind: Namespace
metadata:
  name: baseline-ns
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.22
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: v1.22
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: v1.22

Enforcement Modes

  • Enforce: Pods violating the policy are denied

  • Warn: Violations show warning messages but allow pods

  • Audit: Violations generate audit log entries

Service Accounts and RBAC

Limit API access by controlling service account token mounting:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
automountServiceAccountToken: false

Why disable token mounting?

  • Service account tokens provide cluster API access

  • Many applications don't need this access

  • Follows principle of least privilege

  • Removes potential attack vector

RuntimeClass: Enhanced Isolation

Select different container runtimes with varying security isolation levels:

apiVersion: v1
kind: Pod
metadata:
  name: kuard
  labels:
    app: kuard
spec:
  runtimeClassName: firecracker
  containers:
  - image: gcr.io/kuar-demo/kuard-amd64:blue
    name: kuard
    ports:
    - containerPort: 8080
      name: http
      protocol: TCP

Runtime Options

  • runc: Standard OCI runtime (default)

  • kata: VM-based containers (stronger isolation)

  • firecracker: Lightweight VMs (AWS Lambda technology)

  • gVisor: User-space kernel (Google's container sandbox)

Network Policy: Traffic Control

Implement "default deny, explicit allow" network security:

Default Deny Policy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Selective Allow Policy

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: access-kuard
spec:
  podSelector:
    matchLabels:
      app: kuard
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: test-source

Network Policy Key Concepts

  • Additive nature: Multiple policies combine (logical OR)

  • Explicit definition required: Once matched by NetworkPolicy, all traffic must be explicitly allowed

  • Controller dependency: Requires CNI support (Calico, Cilium, Weave Net)

Service Mesh Security

Add application-layer security with service mesh:

Key Benefits:

  • Protocol-aware policies (HTTP methods, paths, headers)

  • Mutual TLS (mTLS) for automatic encryption

  • Service identity verification

  • Fine-grained access control

# Example Istio AuthorizationPolicy
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-serviceA-to-serviceB
spec:
  selector:
    matchLabels:
      app: serviceB
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/serviceA"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/*"]

Security Benchmarking with kube-bench

Regular security assessment using CIS Kubernetes Benchmarks:

apiVersion: batch/v1
kind: Job
metadata:
  name: kube-bench
spec:
  template:
    spec:
      hostPID: true
      nodeSelector:
        kubernetes.io/os: linux
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: kube-bench
        image: aquasec/kube-bench:latest
        command: ["kube-bench"]
        volumeMounts:
        - name: var-lib-etcd
          mountPath: /var/lib/etcd
          readOnly: true
        - name: var-lib-kubelet
          mountPath: /var/lib/kubelet
          readOnly: true
        - name: etc-systemd
          mountPath: /etc/systemd
          readOnly: true
        - name: etc-kubernetes
          mountPath: /etc/kubernetes
          readOnly: true
        - name: usr-bin
          mountPath: /usr/local/mount-from-host/bin
          readOnly: true
      restartPolicy: Never
      volumes:
      - name: var-lib-etcd
        hostPath:
          path: "/var/lib/etcd"
      - name: var-lib-kubelet
        hostPath:
          path: "/var/lib/kubelet"
      - name: etc-systemd
        hostPath:
          path: "/etc/systemd"
      - name: etc-kubernetes
        hostPath:
          path: "/etc/kubernetes"
      - name: usr-bin
        hostPath:
          path: "/usr/bin"

Understanding kube-bench Output

  • [PASS]: Compliant configurations

  • [FAIL]: Security gaps requiring attention

  • [WARN]: Potential issues to investigate

Image Security

Container security extends beyond runtime controls:

Secure Development Practices

  • Keep code and applications within pods secure

  • Use minimal base images

  • Regular vulnerability scanning

Registry Security

  • Scan images for known vulnerabilities

  • Use trusted registries

  • Implement image signing and verification

Runtime Security

  • Continuous monitoring for malicious activity

  • Detect intrusions and policy violations

  • Rapid patch deployment for vulnerabilities

Complete Security Strategy

Defense-in-Depth Layers

  1. Pod Security Context - User permissions, filesystem access, capabilities

  2. Pod Security Standards - Baseline, restricted, and privileged policies

  3. AppArmor/SELinux/Seccomp - Kernel-level access controls

  4. RBAC & Service Accounts - API access limitation

  5. RuntimeClass - Container isolation levels

  6. Network Policy - Traffic control and segmentation

  7. Service Mesh - Application-layer security and mTLS

  8. Image Security - Vulnerability management and scanning

  9. Security Benchmarks - Compliance assessment and remediation

Implementation Workflow

  1. Start with defaults - Apply Pod Security Standards

  2. Layer additional controls - Add NetworkPolicy, SecurityContext

  3. Assess compliance - Run kube-bench regularly

  4. Monitor continuously - Use security scanning and monitoring

  5. Iterate and improve - Regular security reviews and updates

Key Security Principles

  • Least Privilege - Minimal permissions and capabilities

  • Defense-in-Depth - Multiple overlapping security layers

  • Default Deny - Block by default, allow by exception

  • Continuous Monitoring - Ongoing security assessment

  • Rapid Response - Quick patching and remediation

Bye 🍻