<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT -->
---
applyTo: '**/*.py'
---

# container-security-guide

> Docker and Kubernetes security hardening guide covering images, builds, runtime, and orchestration

# Container Security Guide

## Overview

Containers introduce a unique attack surface spanning the image build pipeline, container runtime, orchestration layer, and host OS. Security must be applied at every stage of the container lifecycle:

| Stage        | Threats                                           | Key Controls                        |
|--------------|---------------------------------------------------|-------------------------------------|
| Build        | Malicious base images, embedded secrets, bloat    | Minimal images, scanning, signing   |
| Registry     | Image tampering, unauthorized access              | Content trust, access control       |
| Deploy       | Misconfigured pods, excessive privileges          | Admission control, PodSecurity      |
| Runtime      | Container escape, lateral movement, cryptomining  | Seccomp, AppArmor, monitoring       |
| Orchestration| RBAC bypass, API server exposure, secret leaks    | NetworkPolicy, RBAC, external secrets|

This guide covers Docker image and build security, Kubernetes-specific hardening, and runtime protection. It is tailored for teams running containerized workloads on GKE but applies broadly to any Kubernetes distribution.

## When to Use This Skill

- You are writing or reviewing Dockerfiles for production services
- You are configuring Kubernetes security settings (PodSecurityStandards, NetworkPolicies, RBAC)
- You need to harden a container runtime environment against known attack vectors
- You are building a CI/CD pipeline and need image scanning and signing gates
- You are investigating a container security incident or preparing for an audit
- You want to implement defense-in-depth for containerized microservices

## How It Works

### Step 1: Scan Container Images

Scan images for known vulnerabilities before they reach production:

```bash
# Trivy: comprehensive vulnerability scanner
trivy image --severity HIGH,CRITICAL faos-api:latest

# Grype: fast alternative scanner
grype faos-api:latest --only-fixed --fail-on high

# Snyk: SaaS scanner with fix suggestions
snyk container test faos-api:latest --severity-threshold=high

# GCP Artifact Registry: automatic scanning
gcloud artifacts docker images list-vulnerabilities \
  REGION-docker.pkg.dev/PROJECT/REPO/my-app:latest \
  --format=json | jq '.[] | select(.vulnerability.effectiveSeverity == "CRITICAL")'
```

Integrate scanning into CI/CD pipelines with a gate:

```yaml
# GitHub Actions: scan and fail on critical vulnerabilities
- name: Scan container image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: ${{ env.IMAGE }}
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'  # Fail the build on findings
```

### Step 2: Harden Dockerfiles

Build minimal, secure container images following these principles:

- Use minimal base images (distroless, Alpine, or scratch)
- Run as non-root user
- Use multi-stage builds to exclude build tools from production images
- Never embed secrets, credentials, or private keys in images
- Pin base image versions with digest for reproducibility
- Set the filesystem to read-only where possible
- Include health checks for orchestrator integration

### Step 3: Apply PodSecurityStandards

Kubernetes PodSecurityStandards (PSS) define three progressive security profiles:

| Profile      | Level of Security | Use Case                           |
|--------------|-------------------|------------------------------------|
| Privileged   | None              | System-level workloads (kube-system)|
| Baseline     | Moderate          | General workloads, prevents known escalations|
| Restricted   | Strict            | Security-sensitive and multi-tenant workloads|

Apply PSS enforcement at the namespace level:

```bash
# Enforce restricted profile on production namespace
kubectl label namespace faos-api \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/audit=restricted
```

### Step 4: Configure NetworkPolicies

By default, all pods in a Kubernetes cluster can communicate with all other pods. NetworkPolicies implement microsegmentation:

- Start with a default-deny policy for all namespaces
- Explicitly allow only required communication paths
- Use label selectors for fine-grained pod-to-pod rules
- Allow DNS resolution (kube-dns) in every policy

### Step 5: Enable Runtime Monitoring

Runtime security tools detect anomalous container behavior:

```bash
# Falco: runtime threat detection
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
  --namespace falco-system \
  --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl=$SLACK_WEBHOOK

# Falco detects:
# - Shell spawned in container
# - Sensitive file access (/etc/shadow, /etc/passwd)
# - Unexpected network connections
# - Privilege escalation attempts
# - Cryptocurrency miner signatures
```

Runtime protection layers:

| Technology  | Protection Level                        | Performance Impact |
|-------------|-----------------------------------------|-------------------|
| Seccomp     | System call filtering                   | Minimal           |
| AppArmor    | Mandatory access control profiles       | Low               |
| SELinux     | Type enforcement and RBAC               | Low               |
| gVisor      | User-space kernel (full syscall interception)| Moderate      |
| Kata        | VM-level isolation per container        | Higher            |

## Examples

### Example 1: Secure Dockerfile for Python FastAPI App

```dockerfile
# ============================================
# Stage 1: Build dependencies
# ============================================
FROM python:3.12-slim AS builder

# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# Create virtual environment
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

# ============================================
# Stage 2: Production image
# ============================================
FROM python:3.12-slim AS production

# Security: Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

# Install only runtime dependencies (no gcc/build tools)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Copy virtual environment from builder
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# Copy application code
WORKDIR /app
COPY --chown=appuser:appuser ./src ./src

# Security: No secrets in image (use env vars or mounted secrets)
# Security: Read-only filesystem compatible
# Security: Drop all capabilities in K8s securityContext

# Health check for Kubernetes probes
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# Security: Run as non-root user
USER appuser

# Security: Use exec form (no shell injection risk)
ENTRYPOINT ["uvicorn", "src.main:app"]
CMD ["--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
```

Security features in this Dockerfile:

| Feature                  | Security Benefit                                    |
|--------------------------|-----------------------------------------------------|
| Multi-stage build        | Build tools not in production image (smaller attack surface)|
| `python:3.12-slim`      | Minimal base image (fewer vulnerabilities)          |
| Non-root user            | Prevents container escape to host root              |
| `--no-cache-dir`         | No pip cache (smaller image, no cached credentials) |
| `--no-install-recommends`| Minimal OS packages                                |
| `rm -rf /var/lib/apt`   | No package manager cache                            |
| Exec form ENTRYPOINT    | No shell injection via CMD override                 |
| HEALTHCHECK             | Enables K8s liveness/readiness probes               |

### Example 2: Kubernetes NetworkPolicy for Namespace Isolation

```yaml
# 1. Default deny all ingress and egress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: faos-api
spec:
  podSelector: {}  # Applies to all pods in namespace
  policyTypes:
    - Ingress
    - Egress

---
# 2. Allow DNS resolution (required for service discovery)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: faos-api
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

---
# 3. Allow ingress from gateway to API pods only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-gateway-to-api
  namespace: faos-api
spec:
  podSelector:
    matchLabels:
      app: faos-api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: faos-gateway
          podSelector:
            matchLabels:
              app: gateway
      ports:
        - protocol: TCP
          port: 8000

---
# 4. Allow API pods to reach database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-database
  namespace: faos-api
spec:
  podSelector:
    matchLabels:
      app: faos-api
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/8  # Cloud SQL private IP range
      ports:
        - protocol: TCP
          port: 5432  # PostgreSQL

---
# 5. Allow API pods to reach Redis
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-redis
  namespace: faos-api
spec:
  podSelector:
    matchLabels:
      app: faos-api
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: faos-cache
          podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
```

### Example 3: PodSecurityStandard (Restricted) Configuration

```yaml
# Pod specification compliant with PSS restricted profile
apiVersion: apps/v1
kind: Deployment
metadata:
  name: faos-api
  namespace: faos-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: faos-api
  template:
    metadata:
      labels:
        app: faos-api
    spec:
      # Security: Use dedicated service account (not default)
      serviceAccountName: my-app-sa
      automountServiceAccountToken: false  # Disable unless needed

      # Security: Prevent privilege escalation via hostPID/hostNetwork
      hostPID: false
      hostNetwork: false
      hostIPC: false

      # Security: Set filesystem group for shared volumes
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534      # nobody user
        runAsGroup: 65534
        fsGroup: 65534
        seccompProfile:
          type: RuntimeDefault

      containers:
        - name: faos-api
          image: REGION-docker.pkg.dev/PROJECT/REPO/my-app@sha256:abc123...
          ports:
            - containerPort: 8000
              protocol: TCP

          # Security: Container-level security context
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            runAsUser: 65534
            capabilities:
              drop:
                - ALL
            seccompProfile:
              type: RuntimeDefault

          # Resource limits (prevent resource abuse)
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 1000m
              memory: 512Mi

          # Health probes
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 30
          readinessProbe:
            httpGet:
              path: /ready
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 10

          # Mount secrets from external secret manager (not K8s Secrets)
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: faos-api-secrets
                  key: database-url

          # Writable directories for temp files (read-only root filesystem)
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: cache
              mountPath: /app/.cache

      volumes:
        - name: tmp
          emptyDir:
            sizeLimit: 100Mi
        - name: cache
          emptyDir:
            sizeLimit: 50Mi
```

## Best Practices

### Do This

- Use distroless or slim base images to minimize the attack surface
- Scan images in CI/CD and block deployments with critical or high vulnerabilities
- Sign images with cosign or Notary and verify signatures with Binary Authorization
- Run all containers as non-root with `runAsNonRoot: true`
- Drop all Linux capabilities with `capabilities.drop: [ALL]`
- Set `readOnlyRootFilesystem: true` and mount writable directories as emptyDir volumes
- Apply PodSecurityStandards at `restricted` level for production namespaces
- Implement default-deny NetworkPolicies in every namespace
- Use external secret managers (GCP Secret Manager, HashiCorp Vault) instead of K8s Secrets
- Pin image references by digest (`@sha256:...`) rather than mutable tags
- Enable Seccomp profiles (at minimum `RuntimeDefault`) for all containers
- Implement pod disruption budgets alongside security to maintain availability

### Don't Do This

- Do not use `latest` tag for production images -- it is mutable and unpredictable
- Do not run containers as root or with `privileged: true`
- Do not embed secrets, API keys, or credentials in Docker images
- Do not expose the Docker socket (`/var/run/docker.sock`) to containers
- Do not use `hostPID`, `hostNetwork`, or `hostIPC` unless absolutely required
- Do not skip NetworkPolicies -- default Kubernetes networking allows unrestricted pod-to-pod traffic
- Do not grant `cluster-admin` ClusterRole to application service accounts
- Do not auto-mount service account tokens (`automountServiceAccountToken: false` by default)
- Do not install shells (bash, sh) in production images if they are not needed
- Do not use package managers (apt, apk) at runtime -- install everything at build time

## Security Checklist

### Image Security

- [ ] Base images are minimal (distroless, Alpine, or slim variants)
- [ ] Images are scanned for vulnerabilities in CI/CD with a blocking gate
- [ ] No secrets, credentials, or private keys are embedded in images
- [ ] Multi-stage builds exclude build tools from production images
- [ ] Images are signed and verified before deployment (cosign / Binary Authorization)
- [ ] Image references use digests (`@sha256:...`) not mutable tags
- [ ] Base images are regularly updated to include security patches

### Build Security

- [ ] Dockerfiles use a non-root USER directive
- [ ] `.dockerignore` excludes `.env`, `.git`, `node_modules`, and other sensitive files
- [ ] Build arguments do not contain secrets (use BuildKit secret mounts instead)
- [ ] Layer caching does not leak sensitive data between stages
- [ ] HEALTHCHECK is defined for orchestrator integration

### Runtime Security

- [ ] All containers run as non-root (`runAsNonRoot: true`)
- [ ] All capabilities are dropped (`capabilities.drop: [ALL]`)
- [ ] Root filesystem is read-only (`readOnlyRootFilesystem: true`)
- [ ] Seccomp profile is set to `RuntimeDefault` or a custom profile
- [ ] Resource requests and limits are defined for all containers
- [ ] Service account tokens are not auto-mounted unless required

### Kubernetes Security

- [ ] PodSecurityStandards are enforced at `restricted` or `baseline` level
- [ ] Default-deny NetworkPolicies are applied in every namespace
- [ ] RBAC follows least privilege -- no broad ClusterRole bindings
- [ ] Admission controllers validate configurations before deployment
- [ ] Secrets are managed externally (GCP Secret Manager, Vault, ExternalSecrets)
- [ ] Pod disruption budgets ensure availability during security updates
- [ ] Runtime monitoring (Falco or equivalent) is deployed

## Related Skills

- @cis-benchmarks -- CIS Docker and Kubernetes Benchmark automated scanning
- @cloud-security-patterns -- cloud-native security architectures for GCP, AWS, Azure
- @owasp-top10 -- application-layer security for containerized web applications

## Additional Resources

- [NIST SP 800-190](https://csrc.nist.gov/publications/detail/sp/800-190/final) -- Application Container Security Guide
- [Kubernetes Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) -- official PSS documentation
- [Docker Security Best Practices](https://docs.docker.com/develop/security-best-practices/) -- official Docker guidance
- [Kubernetes Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) -- NetworkPolicy reference
- [Falco Runtime Security](https://falco.org/) -- open-source container runtime threat detection
- [cosign](https://github.com/sigstore/cosign) -- container image signing and verification
- [Trivy](https://github.com/aquasecurity/trivy) -- comprehensive container vulnerability scanner
- [GKE Security Overview](https://cloud.google.com/kubernetes-engine/docs/concepts/security-overview) -- GKE-specific security features
