Skip to content

Follow-up: Enforce Secrets Manager consumption for namespace workloads #36

Description

@lweberru

Background

In issue #35 we implemented namespace-scoped Kubernetes access and deterministic metadata binding to the app landing zone Secrets Manager instance via namespace annotations.

Current state:

  • stackit.cloud/secretsmanager-instance-id is set on managed namespaces.
  • This is a stable contract, but does not yet enforce workload-side secret consumption policy.

Goal

Add enforceable controls so workloads in managed namespaces must use the intended Secrets Manager integration path instead of unmanaged plain Kubernetes secrets.

Scope (proposal)

  1. Define enforcement strategy (admission policy and/or operator pattern).
  2. Add module-level toggles for enforcement mode.
  3. Implement policy resources and defaults for namespace-service-enabled landing zones.
  4. Add tests for allowed/denied paths.
  5. Document rollout and migration strategy.

Non-goals

  • Breaking existing workloads without a migration path.
  • Immediate hard-block in all existing namespaces by default.

Acceptance Criteria

  • Namespaces managed through namespace service can be configured with enforce mode.
  • Direct plain secret usage can be denied (configurable).
  • Approved Secrets Manager integration path remains functional.
  • Tests cover both compliant and non-compliant examples.

Context

Activity

  1. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Aufbauend auf dem aktuellen Stand aus #35 und den heutigen Diskussionen schlage ich folgende Zielarchitektur vor.

    Vorschlag: Durchsetzbare Secret-Nutzung

    Kernidee:

    1. STACKIT Secret Manager bleibt Source of Truth.
    2. Ein Sync-Mechanismus stellt Runtime-Secrets für Pods bereit (z. B. External Secrets Operator).
    3. Admission Policy (Kyverno oder Gatekeeper) erzwingt, dass Entwickler keine direkten Kubernetes Secrets anlegen.
    4. RBAC entzieht Dev-Rollen Lesen/Erstellen von Secrets.

    Damit erreichen wir:

    • Keine Secret-Werte in Git.
    • Kein manuelles Secret-Handling durch App-Teams.
    • Klarer, auditierbarer Pfad pro Namespace.

    Konkreter Rollout-Vorschlag

    Phase 0: Audit / Dry-Run

    • Admission-Regeln zuerst im Audit-Modus.
    • Sichtbarkeit auf Verstöße ohne sofortigen Block.

    Phase 1: Soft Enforcement

    • Direkte Secret-Erstellung in namespace-service-Namespaces verhindern.
    • Break-glass-Ausnahmen über explizite, zeitlich begrenzte Labels/Annotations.

    Phase 2: Strict Enforcement

    • Hard Deny für direkte Secret-Erstellung.
    • Optional zusätzlich: harte Bindung an namespace-gebundene SM-Instanz (stackit.cloud/secretsmanager-instance-id).

    Terraform-/Modul-Integration (Vorschlag)

    Neue Konfiguration unter landing_zones[].namespace_service:

    • secrets_enforcement.enabled (bool)
    • secrets_enforcement.mode (audit|soft|strict)
    • secrets_enforcement.policy_engine (kyverno|gatekeeper)
    • secrets_enforcement.allow_opaque_secret_types (optional list)
    • secrets_enforcement.break_glass (optional object mit allowlist + ttl)

    Outputs:

    • Effektive Enforcement-Config je Landing Zone
    • Policy-Objekt-Namen / Status-Hinweise

    Tests (akzeptanznah)

    1. Allowed: ExternalSecret-Flow (oder definierter Integrationspfad) funktioniert.
    2. Denied: kind: Secret im Strict-Mode wird geblockt.
    3. Audit: Verstoß wird gemeldet, aber nicht geblockt.
    4. Break-glass: Ausnahme greift nur im erlaubten Rahmen.

    Offene Entscheidungen zur Abstimmung

    1. Policy Engine: Kyverno oder Gatekeeper als Standard?
    2. Sync-Mechanismus: ESO als Standardpfad festlegen?
    3. Startmodus für neue Namespaces: audit oder soft?
    4. Umgang mit bestehendem Legacy-Workload: globaler Cutover oder pro Namespace Migrationsfenster?
    5. Break-glass: erlaubt oder vollständig verbieten?
    6. Sollen wir Secret komplett verbieten oder bestimmte Typen (z. B. Token) zulassen?
    7. Sollen Dev-Rollen get/list/watch secrets grundsätzlich verlieren, auch in Nicht-Enforcement-Namespaces?
    8. Wie strikt soll die Bindung an die Namespace-Annotation stackit.cloud/secretsmanager-instance-id werden?
    9. Wollen wir zuerst nur Corporate LZs erzwingen oder Corporate + Public?
    10. Welche Nachweise brauchen wir für Compliance (Audit-Events, regelmäßiger Report, CI-Checks)?

    Wenn wir diese 10 Punkte entscheiden, kann ich daraus ein konkretes Implementierungs-Design inkl. Terraform-Schema, Policy-Regeln und Tests in kleinen PR-fähigen Schritten ableiten.

  2. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Decision update (confirmed)

    Wir übernehmen die vorgeschlagenen Defaults und ergänzen explizit: Das gesamte Secrets-Enforcement-Feature bleibt optional/aktivierbar (opt-in).

    Finale Entscheidungen:

    1. Policy Engine
    • Default: Kyverno
    1. Sync-Pfad
    • Default: External Secrets Operator (ESO)
    1. Startmodus
    • Bestehende Namespaces: audit
    • Neue namespace-service Namespaces: soft
    1. Migration
    • Pro Namespace mit definiertem Migrationsfenster und Deadline
    1. Break-glass
    • Erlaubt, aber zeitlich begrenzt und auditpflichtig
    1. Secret-Policy
    • Direkte Secret-Erstellung wird denied
    • Nur explizit allowlistete technische Ausnahmen
    1. RBAC
    • Dev-Rollen ohne get/list/watch auf Secrets
    1. Binding
    • Strikte Bindung an namespace-Annotation stackit.cloud/secretsmanager-instance-id
    1. Scope
    • Start mit Corporate, danach Public
    1. Compliance
    • Audit-Events, regelmäßiger Report, CI-Policy-Checks

    Zusätzliche Leitplanke (wichtig):

    • Optional/Aktivierbar: Enforcement wird nur angewendet, wenn explizit aktiviert.
    • Vorgeschlagener Schalter: namespace_service.secrets_enforcement.enabled = true|false (Default: false).
    • Ohne Aktivierung gilt der bisherige Zustand unverändert (keine impliziten Breaking Changes).

    Nächster Umsetzungsschritt:

    • Terraform-Schema + Policies so schneiden, dass jede Landing Zone Enforcement separat aktivieren/deaktivieren kann.
  3. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Milestone 1 umgesetzt (Schema + Feature Flags + Groundwork)

    Status: done

    Implementiert:

    • Optionales, aktivierbares Secrets-Enforcement unter landing_zones[].namespace_service.secrets_enforcement
      • enabled (default: false)
      • mode (audit|soft|strict, default: audit)
      • policy_engine (kyverno|gatekeeper, default: kyverno)
      • allow_opaque_secret_types
      • break_glass (enabled, ttl_hours, principals)
    • Validierungen für mode/policy_engine/break_glass.ttl_hours
    • Resolved locals für enforcement-Settings in namespace-service.tf
    • Namespace-Annotations als Groundwork:
      • stackit.cloud/secrets-enforcement-enabled
      • stackit.cloud/secrets-enforcement-mode
      • stackit.cloud/secrets-policy-engine
    • RBAC-Feature-Flag groundwork:
      • Secret-Rechte werden nur vergeben, wenn secrets_enforcement.enabled == false
    • Plan-stabile Outputs ergänzt:
      • landing_zone_namespace_secret_enforcement
      • landing_zone_namespace_service_requests.secrets_enforcement

    Validierung:

    • tofu validate erfolgreich

    Hinweis:

    • Es sind noch keine Admission-Policy-Ressourcen (Kyverno/Gatekeeper) ausgerollt; das folgt in Milestone 2.
    • Verhalten bleibt ohne Aktivierung unverändert (opt-in, default off).
  4. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Milestone 2 (Teil 1) umgesetzt: Kyverno Policy-Rollout (opt-in)

    Status: in progress

    Neu implementiert:

    • Namespace-level Kyverno Policy als opt-in Resource:
      • kubernetes_manifest.landing_zone_secret_enforcement_policy
      • wird nur erzeugt, wenn:
        • namespace_service.secrets_enforcement.enabled = true
        • namespace_service.secrets_enforcement.policy_engine = "kyverno"
    • Modus-Abbildung:
      • audit -> validationFailureAction: Audit
      • soft|strict -> validationFailureAction: Enforce
    • Modus-Verhalten:
      • soft: blockt direkte Secret CREATE
      • strict: blockt direkte Secret CREATE/UPDATE/PATCH
    • Exemptions:
      • Default-Exemptions für ESO ServiceAccounts
      • optionale zusätzliche Break-glass Principals aus Konfiguration
    • Neues Output:
      • landing_zone_namespace_secret_enforcement_policies

    Guardrail:

    • policy_engine=gatekeeper ist aktuell noch nicht implementiert und wird über check explizit blockiert (statt stiller No-op).

    Validierung:

    • tofu validate erfolgreich

    Offen für Milestone 2 (Teil 2):

    • Gatekeeper-Implementierung oder bewusste Entfernung als Auswahloption
    • präzisere Break-glass TTL-Durchsetzung auf Policy-Ebene
    • Tests für audit/soft/strict (compliant/non-compliant)
  5. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Milestone 2 (Teil 2) umgesetzt: Testabdeckung + Schema-Konsistenz

    Status: done

    Ergänzt/angepasst:

    • Root-Schema erweitert um platform_kubernetes.network.sna_network_prefix_length (Konsistenz zu Modul-Input).
    • Hub-Spoke Tests erweitert um Secrets-Enforcement-Abdeckung:
      • secrets_enforcement_audit_plan
      • secrets_enforcement_strict_plan
      • secrets_enforcement_gatekeeper_not_implemented
    • Bootstrap-freundliche Plan-Tests:
      • Audit/Strict testen die aufgelöste Enforcement-Konfiguration ohne sofortigen Policy-Rollout im ersten Plan.
      • Gatekeeper-Guardrail wird explizit als erwarteter Fehler validiert.

    Validierung:

    • tofu validate erfolgreich
    • tofu test -filter=tests/hub_spoke.tftest.hcl erfolgreich
      • Ergebnis: Success! 4 passed, 0 failed.

    Hinweis:

    • Kyverno Policy-Ressourcen bleiben opt-in und an enabled=true + policy_engine=kyverno gebunden.
    • Gatekeeper bleibt bis zur Implementierung explizit blockiert (klarer Fehler statt stiller No-op).
  6. lweberru commented on Jun 11, 2026

    @lweberru
    CollaboratorAuthor

    Scope update (confirmed): Gatekeeper out, Kyverno-only

    Entsprechend der Abstimmung wurde Gatekeeper aus dem Scope entfernt.

    Umgesetzt:

    • secrets_enforcement ist jetzt Kyverno-only.
    • Konfigurierbare Auswahl policy_engine wurde aus dem Input-Schema entfernt.
    • Gatekeeper-spezifischer Guardrail-Check wurde entfernt.
    • Interne/Output-Engine-Angaben sind auf kyverno harmonisiert.
    • Gatekeeper-Testfall wurde entfernt.

    Validierung:

    • tofu validate erfolgreich
    • tofu test -filter=tests/hub_spoke.tftest.hcl erfolgreich
      • Ergebnis: Success! 3 passed, 0 failed.

    Hinweis:

    • Optional/Aktivierbar bleibt unverändert: Enforcement nur bei secrets_enforcement.enabled = true.
  7. added theissue type on Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestkubernetesterraformPull requests that update terraform code

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions