Co je Container Security?
Container Security zahrnuje všechny praktiky, nástroje a procesy pro zabezpečení kontejnerizovaných aplikací
od build time přes deployment až po runtime. Kontejnery sdílejí kernel hostitelského systému, což přináší
nové bezpečnostní výzvy oproti tradičním virtuálním strojům. Efektivní container security vyžaduje multi-layered
approach pokrývající image scanning, runtime protection, network isolation, secrets management a compliance enforcement.
Proč je Container Security kritická?
Kontejnery změnily způsob, jakým vyvíjíme a deployujeme aplikace, ale také přinesly nové bezpečnostní rizika:
- Sdílený kernel: Všechny kontejnery na hostu sdílejí stejný OS kernel - kernel exploit může kompromitovat celý host
- Image vulnerabilities: 80%+ Docker images obsahují známé CVE zranitelnosti
- Misconfigurations: Privilegované kontejnery, mounted Docker socket, exposed APIs
- Supply chain risks: Untrusted base images, malicious layers, backdoored dependencies
- Runtime threats: Container breakout, lateral movement, crypto mining
- Secrets exposure: Hardcoded credentials, env variables, mounted secrets
- Network attacks: Pod-to-pod lateral movement bez network policies
⚠️ Známé container security incidenty
- Tesla Kubernetes cryptojacking (2018): Nechráněný Kubernetes dashboard použit pro mining
- Docker Hub malicious images: 17 malicious images s 5M+ pullů obsahovaly cryptominers
- RunC vulnerability (CVE-2019-5736): Container breakout umožňující root access na hostu
- Kinsing malware: Exploituje misconfigured Kubernetes pro cryptomining a botnet
Vrstvy Container Security
Defense in Depth přístup
1. Build Time Security
Zabezpečení během image build procesu
- Base image selection (minimal, trusted sources)
- Dockerfile best practices (non-root user, no secrets)
- Image scanning pro CVEs (Trivy, Snyk, Clair)
- Multi-stage builds pro menší attack surface
- Image signing a verification (Cosign, Notary)
2. Registry Security
Zabezpečení container registry
- Private registries s autentizací
- Image vulnerability scanning v registry
- Access control (RBAC, IAM)
- Image retention policies
- Webhook notifications na nové vulnerabilities
3. Orchestration Security (Kubernetes)
Zabezpečení Kubernetes cluster
- Pod Security Standards (Restricted, Baseline)
- Network Policies (CNI-based isolation)
- RBAC pro users a service accounts
- Admission Controllers (OPA, Kyverno)
- Secrets management (Vault, External Secrets)
4. Runtime Security
Monitoring a protection běžících kontejnerů
- Runtime behavior monitoring (Falco, Tetragon)
- Anomaly detection
- Process/file/network monitoring
- Intrusion prevention
- Audit logging
5. Host Security
Zabezpečení underlying infrastructure
- Minimal host OS (COS, Bottlerocket)
- Kernel hardening (AppArmor, SELinux)
- Host patching a updates
- CIS Benchmarks compliance
- Node isolation
Docker Security Best Practices
Bezpečný Dockerfile
# ❌ ŠPATNĚ - Security issues
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
COPY secret.key /app/
ENV DB_PASSWORD="hardcoded123"
USER root
EXPOSE 22
# ✅ DOBŘE - Secure Dockerfile
# 1. Use specific version tag (ne latest)
FROM node:18.17.1-alpine3.18
# 2. Install security updates
RUN apk update && apk upgrade && \
apk add --no-cache dumb-init && \
rm -rf /var/cache/apk/*
# 3. Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 4. Set working directory
WORKDIR /app
# 5. Copy only necessary files
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=nodejs:nodejs . .
# 6. Switch to non-root user
USER nodejs
# 7. Expose only necessary ports
EXPOSE 3000
# 8. Use exec form for CMD (signal handling)
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["node", "server.js"]
# 9. Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js || exit 1
Docker Compose security
# docker-compose.yml
version: '3.8'
services:
app:
image: myapp:1.2.3
# Read-only root filesystem
read_only: true
tmpfs:
- /tmp
- /var/run
# Drop all capabilities, add only needed
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
# Non-root user
user: "1001:1001"
# Security options
security_opt:
- no-new-privileges:true
# Resource limits
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
# Secrets from file (ne environment)
secrets:
- db_password
environment:
- NODE_ENV=production
- DB_HOST=postgres
# NO hardcoded secrets!
networks:
- app_network
secrets:
db_password:
file: ./secrets/db_password.txt
networks:
app_network:
driver: bridge
Image Scanning nástroje
Praktický příklad: Trivy v CI/CD
# GitHub Actions - Trivy scan
name: Container Security Scan
on:
push:
branches: [ main ]
pull_request:
jobs:
trivy_scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fail build on HIGH/CRITICAL
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Trivy config scan (Dockerfile)
uses: aquasecurity/trivy-action@master
with:
scan-type: 'config'
scan-ref: '.'
format: 'table'
# GitLab CI - Trivy integration
container_scanning:
stage: test
image: docker:stable
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
script:
- docker build -t $IMAGE .
# Scan image
- apk add --no-cache curl
- export TRIVY_VERSION=$(curl -s "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
- tar zxvf trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz
- ./trivy image --exit-code 0 --severity LOW,MEDIUM $IMAGE
- ./trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE
# Generate SBOM
- ./trivy image --format cyclonedx --output sbom.json $IMAGE
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
paths:
- sbom.json
Kubernetes Security
Pod Security Standards
Kubernetes definuje tři úrovně pod security policies:
# Privileged - No restrictions (dev only)
# Baseline - Minimal restrictions (prevents known privilege escalations)
# Restricted - Heavily restricted (hardened, follows pod hardening best practices)
# Namespace labeling pro enforcement
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
# Restricted Pod příklad
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
namespace: production
spec:
securityContext:
# Run as non-root
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
# Drop all capabilities
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:1.0.0
securityContext:
# Read-only root filesystem
readOnlyRootFilesystem: true
# Drop all capabilities
capabilities:
drop:
- ALL
# No privilege escalation
allowPrivilegeEscalation: false
# Non-root
runAsNonRoot: true
runAsUser: 1000
# Resource limits
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
# Writable volumes pouze kde nutné
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
Network Policies
# Default Deny All (best practice baseline)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# Allow specific ingress/egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
# Ingress rules
ingress:
- from:
# Only from frontend pods
- podSelector:
matchLabels:
app: frontend
# Only from same namespace
- namespaceSelector:
matchLabels:
name: production
ports:
- protocol: TCP
port: 8080
# Egress rules
egress:
# Allow DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
- podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Allow database
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# Allow external HTTPS (GitHub API, etc)
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
Secrets Management
# ❌ ŠPATNĚ - Secrets jako environment variables
apiVersion: v1
kind: Pod
metadata:
name: bad-pod
spec:
containers:
- name: app
image: myapp
env:
- name: DB_PASSWORD
value: "plain-text-password" # NEVER DO THIS!
---
# ✅ DOBŘE - Kubernetes Secrets s encryption at rest
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: production
type: Opaque
stringData:
username: dbuser
password: "use-sealed-secrets-or-vault"
---
apiVersion: v1
kind: Pod
metadata:
name: good-pod
spec:
containers:
- name: app
image: myapp
# Mount as volume (not env var)
volumeMounts:
- name: db-creds
mountPath: "/etc/secrets"
readOnly: true
volumes:
- name: db-creds
secret:
secretName: db-credentials
---
# ✅ JEŠTĚ LEPŠÍ - External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: prod/db/password
- secretKey: username
remoteRef:
key: prod/db/username
# Použití AWS Secrets Manager, HashiCorp Vault, Google Secret Manager...
Runtime Security
Falco rules příklad
# /etc/falco/falco_rules.local.yaml
# Detekce shell spawned v containeru
- rule: Shell Spawned in Container
desc: Detect shell spawned in container
condition: >
spawned_process and
container and
proc.name in (bash, sh, zsh) and
not proc.pname in (sh, bash, docker, containerd)
output: >
Shell spawned in container
(user=%user.name container_id=%container.id
image=%container.image.repository
proc=%proc.cmdline parent=%proc.pname)
priority: WARNING
tags: [container, shell, mitre_execution]
# Detekce sensitive file reads
- rule: Read Sensitive File
desc: Detect reads of sensitive files
condition: >
open_read and
container and
fd.name in (/etc/shadow, /etc/sudoers, /root/.ssh/id_rsa)
output: >
Sensitive file opened for reading
(user=%user.name file=%fd.name
container=%container.name image=%container.image)
priority: CRITICAL
tags: [filesystem, mitre_credential_access]
# Detekce privilege escalation
- rule: Privilege Escalation via Sudo
desc: Detect privilege escalation using sudo
condition: >
spawned_process and
proc.name = "sudo" and
not user.name = "root"
output: >
Privilege escalation detected
(user=%user.name command=%proc.cmdline)
priority: HIGH
# Detekce crypto mining
- rule: Crypto Miner Detected
desc: Detect known crypto mining processes
condition: >
spawned_process and
proc.name in (xmrig, ethminer, cpuminer)
output: >
Crypto miner detected!
(process=%proc.name cmdline=%proc.cmdline)
priority: CRITICAL
tags: [malware, cryptomining]
Container Security Best Practices - Shrnutí
✅ Build Time
- Používejte minimal base images (alpine, distroless, scratch)
- Specific version tags (ne latest)
- Multi-stage builds pro menší images
- Scan images před push do registry (Trivy, Snyk)
- Non-root user
- No secrets v images nebo Dockerfile
- Sign images (Cosign, Notary)
✅ Registry
- Private registries s RBAC
- Continuous scanning v registry
- Admission control (pouze signed/scanned images)
- Image retention policies
- Vulnerability webhooks a alerting
✅ Kubernetes Deployment
- Pod Security Standards (Restricted pro production)
- Network Policies (default deny all)
- Resource limits (CPU, memory)
- RBAC (least privilege)
- Secrets z external store (Vault, AWS Secrets Manager)
- Admission controllers (OPA, Kyverno)
- Service mesh pro mTLS (Istio, Linkerd)
✅ Runtime
- Runtime monitoring (Falco, Tetragon)
- Anomaly detection a alerting
- Audit logging
- Incident response playbooks
- Regular security audits
❌ Co NEDĚLAT
- Používat latest tag v production
- Run containers as root
- Mount Docker socket do containeru
- Privilegované kontejnery bez důvodu
- Hardcoded secrets v images
- Žádné network policies
- Disable security features pro "rychlejší debugging"
- Ignorovat scan results