Zum Inhalt

Guardrails im Detail

Diese Seite beschreibt alle Guardrails der ayedo Software Delivery Plattform im Detail. Guardrails sind automatische Sicherheitsmaßnahmen, die mittels Kyverno Policies durchgesetzt werden.

Standard-Modus: Enforce

Die meisten Guardrails sind standardmäßig im Enforce-Modus aktiviert und blockieren Deployments, die gegen die Policy verstoßen. Dies verhindert, dass unsichere oder nicht-compliant Konfigurationen in Production landen.

Security Guardrails

Verbot privilegierter Container

Compliance: ISO 27001 Annex A 8.18, NIST SP 800-171 3.1.7

Zweck

Minimiert Blast Radius von Container- und OS-Schwachstellen durch Verhinderung von Root-Zugriff.

Problem

Viele Container Runtime- und Betriebssystem-Schwachstellen benötigen Root-Rechte, um zu einer Bedrohung zu werden. Anwendungen sollten nur als Root laufen, wenn absolut notwendig.

Leider werden viele Dockerfiles - und Container Base Images - heute standardmäßig als Root ausgeliefert. Dies macht es einfach, versehentlich Code mit Root-Rechten in Production zu deployen.

Wie hilft die ayedo SDP?

Die ayedo SDP schützt Sie davor, versehentlich Anwendungen als Root zu deployen. Kyverno prüft automatisch:

  • securityContext.runAsNonRoot muss true sein
  • securityContext.runAsUser darf nicht 0 sein (Root-UID)

Fehlerme

ldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Pod/default/myapp for resource violation:

disallow-privileged-containers:
  validate-runAsNonRoot: 'validation error: Running as root is not allowed.
  The field spec.securityContext.runAsNonRoot must be set to true.'

Lösung

Option 1: Dockerfile anpassen (bevorzugt)

FROM node:18-alpine

# Create non-root user
RUN addgroup -g 1000 appuser && \
    adduser -D -u 1000 -G appuser appuser

# Switch to non-root user (numeric UID)
USER 1000

COPY --chown=1000:1000 . /app
WORKDIR /app

CMD ["node", "server.js"]

Option 2: Pod SecurityContext

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
  containers:
    - name: app
      image: myapp:1.0.0

Best Practice

Bevorzugen Sie Änderungen am Dockerfile, damit Ihre Anwendung auch in Development und Testing als non-root läuft. Je kleiner der Unterschied zwischen den Umgebungen, desto weniger Überraschungen.

Weitere Informationen:


Keine latest Tags

Compliance: ISO 27001 Annex A 8.32 (Change Management)

Zweck

Verhindert unerwartete Änderungen und ermöglicht kontrollierte, nachvollziehbare Deployments.

Problem

Die Verwendung des :latest Tags führt zu:

  • Inkonsistenten Deployments: Schwer nachzuvollziehen, welche Version deployed ist
  • Rollback-Problemen: Schwierig, auf vorherige Version zurückzukehren
  • Unerwarteten Änderungen: :latest ist nur ein Tag, keine dynamische Referenz

Häufiges Missverständnis

Auch wenn kein Tag angegeben wird, nutzt Kubernetes :latest - aber das bedeutet NICHT, dass die neueste Version verwendet wird! :latest ist nur ein Tag wie jeder andere.

Wie hilft die ayedo SDP?

Kyverno blockiert Images mit :latest Tag oder ohne explizites Tag.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Pod/default/myapp for resource violation:

disallow-latest-tag:
  validate-image-tag: 'validation error: Image tag "latest" is not allowed.
  Images must use explicit version tags.'

Lösung

Verwenden Sie immer explizite, immutable Tags:

Gut:

image: harbor.ayedo.cloud/myapp:v1.2.3
image: harbor.ayedo.cloud/myapp:sha256-abc123def
image: myapp:2024-01-15-f6451806

Schlecht:

image: myapp:latest
image: myapp  # Impliziert :latest
image: myapp:dev  # Mutable tag
image: myapp:prod  # Mutable tag

Best Practice für Tags

  • Semantic Versioning: v1.2.3, v2.0.0
  • Git Commit Hash: sha256-f6451806, git-abc123
  • Timestamp + Hash: 2024-01-15-abc123
  • Behandeln Sie alle Tags als immutable: Erstellen Sie immer neue Tags statt bestehende zu überschreiben

Weitere Informationen:


Resource Requests erforderlich

Compliance: ISO 27001 Annex A 8.6 (Kapazitätsplanung)

Zweck

Verhindert Downtime durch Resource Exhaustion und ermöglicht optimale Pod-Platzierung.

Problem

Eine Hauptursache für Anwendungsausfälle ist unzureichende Kapazität:

  • CPU-Überlastung: Node erreicht 100% CPU → Anwendung läuft langsam
  • Memory Pressure: Node hat zu wenig Memory → Page Cache wird kleiner → Anwendung langsamer
  • OOM Killer: Bei extremem Memory Pressure tötet der Out-of-Memory Killer Prozesse

Lösung

Kubernetes erlaubt es, Resource Requests und Limits zu definieren. Dies bietet zwei Vorteile:

  1. Scheduling: Pods werden nur auf Nodes platziert, die genug Ressourcen haben
  2. Isolation: Pods können ihre Limits nicht überschreiten und schützen so andere Pods

Wie hilft die ayedo SDP?

Kyverno erzwingt, dass alle Container CPU und Memory Requests definieren müssen.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Deployment/default/myapp for resource violation:

require-requests-limits:
  validate-resources: 'validation error: CPU and memory resource requests
  are required. Container "myapp" is missing requests.'

Lösung

Definieren Sie Requests (und optional Limits) für alle Container:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: myapp
          image: myapp:v1.0.0
          resources:
            requests:
              memory: "256Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"

Sizing Guidelines

Requests: Was die Anwendung normal benötigt

  • Start mit konservativen Schätzungen
  • Beobachten Sie tatsächliche Nutzung in VictoriaMetrics/Grafana
  • Passen Sie basierend auf Daten an

Limits: Maximum, das die Anwendung nutzen darf

  • CPU Limit: 2-3x Request (Bursts erlauben)
  • Memory Limit: 1.5-2x Request (OOM vermeiden)
  • Für kritische Workloads: Limit = Request (garantierte Ressourcen)

CPU-Einheiten:

  • 1000m = 1 = 1 CPU Core
  • 100m = 0.1 CPU Core
  • 500m = 0.5 CPU Core

Memory-Einheiten:

  • Mi = Mebibyte (1024²)
  • Gi = Gibibyte (1024³)
  • Beispiel: 256Mi, 1Gi, 512Mi

Weitere Informationen:


Network Policies erforderlich

Compliance: ISO 27001 Annex A 8.20 (Networks Controls), BSI APP.4.4.A19

Zweck

Implementiert Netzwerk-Segmentierung und minimiert laterale Bewegung bei Kompromittierung.

Problem

Ohne Network Policies können alle Pods miteinander kommunizieren. Bei einer Kompromittierung kann ein Angreifer sich lateral durch das Cluster bewegen.

Wie hilft die ayedo SDP?

Kyverno erzwingt, dass jeder Namespace mindestens eine NetworkPolicy definiert hat. Cilium setzt diese Policies auf Kernel-Ebene durch.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Namespace/myapp for resource violation:

require-networkpolicy:
  check-networkpolicy-exists: 'validation error: Namespace must have at
  least one NetworkPolicy defined.'

Lösung

Definieren Sie NetworkPolicies für Ihren Namespace:

Beispiel: Default Deny All

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

Beispiel: Allow from Ingress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
  namespace: myapp
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

Beispiel: Allow to Database

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-to-database
  namespace: myapp
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              name: database
      ports:
        - protocol: TCP
          port: 5432
    - to:  # DNS
        - namespaceSelector:
            matchLabels:
              name: kube-system
      ports:
        - protocol: UDP
          port: 53

Best Practice

  1. Start mit Default Deny: Blockieren Sie zunächst allen Traffic
  2. Whitelist Approach: Erlauben Sie explizit nur notwendigen Traffic
  3. Label-basiert: Nutzen Sie Labels statt IP-Adressen
  4. Testen Sie: Verifizieren Sie Policies mit kubectl exec ... -- curl

Weitere Informationen:


Trusted Registries

Compliance: ISO 27001 Annex A 8.19 (Security in Development/Support)

Zweck

Verhindert Nutzung von Images aus nicht-vertrauenswürdigen Quellen und reduziert Supply Chain Risiken.

Problem

Images aus öffentlichen oder unbekannten Registries können:

  • Malware enthalten
  • Schwachstellen haben
  • Backdoors enthalten
  • Nicht compliance-konform sein

Wie hilft die ayedo SDP?

Kyverno erlaubt nur Images aus konfigurierten vertrauenswürdigen Registries (z.B. Harbor).

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Pod/default/myapp for resource violation:

restrict-image-registries:
  validate-registries: 'validation error: Image must be from an approved
  registry. Allowed registries: harbor.ayedo.cloud'

Lösung

Pushen Sie Ihre Images zu Harbor und referenzieren Sie sie von dort:

Falsch:

image: nginx:latest
image: docker.io/myapp:v1.0
image: ghcr.io/user/myapp:v1.0

Richtig:

image: harbor.ayedo.cloud/myproject/myapp:v1.0.0
image: harbor.ayedo.cloud/myproject/nginx:1.25-alpine

Image Mirror Workflow

Für externe Images:

  1. Pull von öffentlicher Registry: docker pull nginx:1.25-alpine
  2. Re-tag: docker tag nginx:1.25-alpine harbor.ayedo.cloud/myproject/nginx:1.25-alpine
  3. Scan: Harbor scannt automatisch auf Vulnerabilities
  4. Push: docker push harbor.ayedo.cloud/myproject/nginx:1.25-alpine
  5. Verwenden Sie das gespiegelte Image

Weitere Informationen:


Reliability Guardrails

Minimum Replicas

Compliance: ISO 27001 Annex A 8.6, GDPR Art. 32 (Availability)

Zweck

Stellt Hochverfügbarkeit sicher und verhindert Single Points of Failure.

Problem

Deployments mit nur 1 Replica haben keinen Schutz gegen:

  • Pod-Ausfälle
  • Node-Ausfälle
  • Rolling Updates (führen zu Downtime)

Wie hilft die ayedo SDP?

Kyverno erzwingt mindestens 2 Replicas für Deployments in Production-Namespaces.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Deployment/production/myapp for resource violation:

minimum-replicas:
  check-replicas: 'validation error: Minimum 2 replicas required in
  production namespaces. Current: 1'

Lösung

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
spec:
  replicas: 3  # Mindestens 2, besser 3+
  template:
    # ...

Replica Count Guidelines

  • Development: 1 Replica OK
  • Staging: 2 Replicas
  • Production: 3+ Replicas
  • Kritische Services: 5+ Replicas über mehrere Zones

Weitere Informationen:


PodDisruptionBudgets

Compliance: ISO 27001 Annex A 8.6, GDPR Art. 32 (Resilience)

Zweck

Schützt vor Downtime während Wartungsarbeiten und Node-Drains.

Problem

Ohne PodDisruptionBudget kann Kubernetes während:

  • Rolling Updates
  • Node Drains
  • Cluster Upgrades

alle Pods einer Anwendung gleichzeitig beenden, was zu Downtime führt.

Wie hilft die ayedo SDP?

Kyverno warnt, wenn Deployments mit mehreren Replicas keine PodDisruptionBudgets haben (Audit-Mode).

Lösung

Definieren Sie PodDisruptionBudgets:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: myapp-pdb
  namespace: production
spec:
  minAvailable: 2  # Mindestens 2 Pods müssen laufen
  selector:
    matchLabels:
      app: myapp

Alternativ mit Prozent:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: myapp-pdb
spec:
  maxUnavailable: 25%  # Maximal 25% dürfen gleichzeitig down sein
  selector:
    matchLabels:
      app: myapp

PDB Guidelines

  • minAvailable: Garantiert Mindestanzahl laufender Pods
  • maxUnavailable: Limitiert gleichzeitig ausfallende Pods
  • Für 3 Replicas: minAvailable: 2 oder maxUnavailable: 1
  • Für 5 Replicas: minAvailable: 3 oder maxUnavailable: 2

Weitere Informationen:


Kein Pod ohne Controller

Compliance: ISO 27001 Annex A 8.6

Zweck

Stellt sicher, dass Pods automatisch neu gestartet werden und Self-Healing funktioniert.

Problem

"Nackte" Pods (ohne Deployment, StatefulSet, DaemonSet, Job) werden bei Ausfall nicht neu gestartet.

Wie hilft die ayedo SDP?

Kyverno verhindert direkte Pod-Erstellung und erzwingt Nutzung von Controllern.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Pod/default/myapp for resource violation:

require-controller:
  check-controller: 'validation error: Pods must be created via Deployment,
  StatefulSet, DaemonSet, or Job.'

Lösung

Verwenden Sie Controller statt direkter Pod-Erstellung:

Falsch:

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: myapp
      image: myapp:v1.0.0

Richtig:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: myapp:v1.0.0

Weitere Informationen:


Operational Guardrails

Keine LoadBalancer Services

Compliance: Kostenoptimierung, Security

Zweck

Erzwingt Nutzung von Ingress für externe Zugriffe und reduziert Kosten.

Problem

LoadBalancer Services:

  • Kosten Geld (Cloud Provider Fees)
  • Sind schwer zu verwalten (viele externe IPs)
  • Keine zentralen TLS-Zertifikate
  • Kein einheitliches Routing

Wie hilft die ayedo SDP?

Kyverno erlaubt nur ClusterIP und NodePort Services, externe Zugriffe via Ingress.

Fehlermeldung

Error from server: admission webhook "validate.kyverno.svc" denied the request:

policy Service/default/myapp for resource violation:

disallow-loadbalancer:
  check-service-type: 'validation error: LoadBalancer Services are not
  allowed. Use Ingress instead.'

Lösung

Verwenden Sie Ingress:

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  type: ClusterIP  # Statt LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: myapp
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - myapp.example.com
      secretName: myapp-tls
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myapp
                port:
                  number: 80

Weitere Informationen:


Kein lokaler Storage (emptyDir)

Compliance: ISO 27001 Annex A 8.13 (Information Backup)

Zweck

Verhindert Datenverlust bei Pod-Neustart und erzwingt Nutzung von persistentem Storage.

Problem

emptyDir Volumes:

  • Gehen bei Pod-Neustart verloren
  • Können nicht gesichert werden
  • Sind nicht hochverfügbar

Wie hilft die ayedo SDP?

Kyverno warnt vor emptyDir-Nutzung (Audit-Mode) oder blockiert diese (Enforce-Mode, konfigurierbar).

Lösung

Verwenden Sie PersistentVolumeClaims:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myapp-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: longhorn
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: myapp
          volumeMounts:
            - name: data
              mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: myapp-data

emptyDir erlaubt für:

  • Temporäre Caches
  • Scratch Space
  • Data-sharing zwischen Containern im selben Pod
  • NICHT für persistente Daten!

Weitere Informationen:


Job TTL (Time to Live)

Compliance: Kostenoptimierung, Resource Management

Zweck

Verhindert, dass abgeschlossene Jobs unbegrenzt im Cluster verbleiben.

Problem

Jobs ohne TTL bleiben nach Abschluss im Cluster und:

  • Verbrauchen API Server-Ressourcen
  • Machen kubectl get pods unübersichtlich
  • Stapeln sich über Zeit

Wie hilft die ayedo SDP?

Kyverno mutiert Jobs automatisch und fügt ttlSecondsAfterFinished hinzu (falls nicht definiert).

Lösung

Automatisch (via Kyverno Mutation):

Jobs erhalten automatisch ein TTL von 3600 Sekunden (1 Stunde).

Manuell konfigurieren:

apiVersion: batch/v1
kind: Job
metadata:
  name: data-processing
spec:
  ttlSecondsAfterFinished: 3600  # Lösche nach 1 Stunde
  template:
    spec:
      containers:
        - name: processor
          image: myapp:v1.0.0
      restartPolicy: OnFailure

TTL Guidelines

  • Short-lived Jobs: 300-600 Sekunden (5-10 Minuten)
  • Standard Jobs: 3600 Sekunden (1 Stunde)
  • Debug Jobs: 86400 Sekunden (24 Stunden)
  • Wichtige Logs: Sichern Sie Logs vor Löschung!

Weitere Informationen:


Default Pod Topology Spread

Compliance: ISO 27001 Annex A 8.6 (High Availability)

Zweck

Verteilt Pods automatisch über Nodes für bessere Availability.

Problem

Ohne Topology Spread Constraints können alle Replicas auf demselben Node landen, was zu Single Point of Failure führt.

Wie hilft die ayedo SDP?

Kyverno fügt automatisch Default Topology Spread Constraints hinzu, die Pods gleichmäßig über Nodes verteilen.

Automatisch angewendet

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app: myapp

Erklärung:

  • maxSkew: 1: Maximal 1 Pod Unterschied zwischen Nodes
  • topologyKey: kubernetes.io/hostname: Verteile über Nodes
  • whenUnsatisfiable: ScheduleAnyway: Soft Constraint (bevorzugt, aber nicht erzwungen)

Manuell überschreiben

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone  # Verteile über Zones
          whenUnsatisfiable: DoNotSchedule  # Hard Constraint
          labelSelector:
            matchLabels:
              app: myapp

Weitere Informationen:


Policy Violations überprüfen

Via Grafana Dashboard

Das Policy as Code Dashboard zeigt alle Policy Violations.

Via kubectl

# Alle Policy Reports anzeigen
kubectl get policyreport -A

# Details zu einem Report
kubectl describe policyreport -n myapp

# Nur Failures
kubectl get policyreport -A -o json | jq '.items[] | select(.summary.fail > 0)'

Via Kyverno CLI

# Policy lokal testen
kyverno apply policy.yaml --resource deployment.yaml

# Cluster-wide Scan
kyverno scan --policy-report

Policy Exceptions

In begründeten Fällen können Ausnahmen gewährt werden:

apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
  name: allow-root-for-special-app
  namespace: special
spec:
  exceptions:
    - policyName: disallow-privileged-containers
      ruleNames:
        - validate-runAsNonRoot
  match:
    any:
      - resources:
          kinds:
            - Pod
          namespaces:
            - special
          names:
            - special-app-*

Exceptions müssen dokumentiert werden!

  • Grund: Warum ist die Ausnahme nötig?
  • Risk Assessment: Welches Risiko wird akzeptiert?
  • Review Date: Wann wird die Ausnahme überprüft?
  • Approval: Wer hat die Ausnahme genehmigt?

Support

Bei Fragen zu Guardrails:

Weiterführende Ressourcen