Skip to main content
This guide walks through taking a cluster from open to a hardened, zero-trust posture. The steps build on each other, and every one can be staged with audit mode before it blocks anything — so you harden without surprise outages.

1. Move to default-deny

The highest-impact change. A new cluster runs defaultMode: allow, so every flow no policy matches passes. Hardening means flipping that backstop to deny, in stages. Start by denying cross-namespace traffic in audit, so you can see what would break before it does:
apiVersion: nyx.tracenyx.io/v1alpha1
kind: NyxClusterConfig
metadata:
  name: cluster
spec:
  defaultMode: deny-cross-namespace
  enforcement: audit
  excludedNamespaces:
    - kube-system
    - kube-public
    - nyx-system
Review the would-deny findings, add explicit allow policies for the cross-namespace traffic that’s legitimate, and once the log is clean, set enforcement: enforce. When you’re ready for full zero-trust, move to defaultMode: deny — now even intra-namespace traffic needs an explicit allow. See Enforcement Modes for the staging detail and NyxClusterConfig for the fields.

2. Lock down egress

Cross-namespace deny handles east-west traffic; egress hardening governs what leaves the cluster. The pattern is default-deny egress, then allowlist only what’s needed — by FQDN (toFqdn.matchName, which applies to HTTPS on 443) and by IP range (toIpBlock). This policy lets the payments workload reach its provider over HTTPS and denies everything else:
apiVersion: nyx.tracenyx.io/v1alpha1
kind: NyxNetworkPolicy
metadata:
  name: payments-egress-allowlist
  namespace: cloudmart-payments
spec:
  podSelector:
    matchLabels:
      app: cloudmart-payments
  priority: 100
  enforcement: enforce
  policyTypes:
    - Egress
  egress:
    - decision: Allow
      toFqdn:
        - matchName: api.stripe.com
      ports:
        - protocol: TCP
          port: 443
Block plaintext egress as a baseline. FQDN matching relies on the TLS handshake, so plain HTTP can’t be matched by name — and production workloads rarely have a good reason to make plaintext outbound calls. Require HTTPS and deny the rest; see FQDN egress.

3. Set platform guardrails

Some rules shouldn’t be overridable by any namespace or application team — blocking known-bad destinations, denying public-internet egress for regulated namespaces, and the like. Put these in a NyxClusterNetworkPolicy in the platform-override band (priority 0–99). Because lower priorities are evaluated first, they win over every namespace and workload policy. This denies all public-internet egress from production, cluster-wide:
apiVersion: nyx.tracenyx.io/v1alpha1
kind: NyxClusterNetworkPolicy
metadata:
  name: deny-public-internet
spec:
  tier: platform
  priority: 50
  enforcement: enforce
  namespaceSelector:
    matchLabels:
      environment: production
  policyTypes:
    - Egress
  egress:
    - decision: Deny
      toIpBlock:
        cidr: 0.0.0.0/0
See Priority System for how the bands resolve.

4. Control who can author policy

Hardening the network is only half the picture — control who can change it.
  • On Scout, policy authorship is tied to your kubectl identity through the binding step: the admission webhook only accepts policies from a recognised identity.
  • On Sentinel and Aegis, SSO and RBAC give you team-based control over who can create or modify policies, with every change attributed in the audit log.
See Tiers.

5. Exclude only what you must

excludedNamespaces in NyxClusterConfig makes a namespace bypass all enforcement, in both directions. Keep the list minimal — typically just the system namespaces that genuinely can’t tolerate policy (kube-system, kube-public, nyx-system). Every excluded namespace is a gap in enforcement. Observability still covers excluded namespaces, so you keep visibility even where you don’t enforce.