# Default-deny plus the narrowest set of exceptions (AUDIT-WP-0005-T03). # # The receiver holds the audit trail, so reachability is part of its threat # model: only the declared sender may write, and only the declared operator # path may read. --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-default-deny namespace: audit-core spec: podSelector: {} policyTypes: [Ingress, Egress] # No rules: everything not permitted below is denied. --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-sender-ingress namespace: audit-core spec: podSelector: matchLabels: app.kubernetes.io/name: audit-core policyTypes: [Ingress] ingress: # user-engine is the only sender. A second sender is a deliberate change # here and a matching entry in AUDIT_CORE_SENDERS — the network rule and # the credential binding must move together. - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: user-engine ports: - {protocol: TCP, port: 8080} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-whitehat-ingress namespace: audit-core spec: podSelector: matchLabels: app.kubernetes.io/name: audit-core policyTypes: [Ingress] ingress: # Governed E2 evidence plane. Both selectors belong to one peer and are # therefore ANDed: only the registered audit-core probe in the dedicated # whitehat namespace reaches this port. Application sender authentication # and tenant scope remain the inner boundary. - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: whitehat podSelector: matchLabels: whitehat.security/plane: "true" whitehat.security/target: audit-core ports: - {protocol: TCP, port: 8080} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-approval-engine-ingress namespace: audit-core spec: podSelector: matchLabels: app.kubernetes.io/name: audit-core policyTypes: [Ingress] ingress: # AUDIT-WP-0009-T09 / AUDIT-IN-0001. Load-bearing approval evidence # (§9.4). Both selectors belong to one peer and are therefore ANDed: # only the approval-engine workload in its own namespace reaches this # port. Splitting them into two list items would turn AND into OR and # admit every pod in either set. # # Narrower than user-engine's namespace-only rule on purpose: this is a # new sender, and a new rule should not inherit an older rule's breadth. # user-engine's policy is deliberately left unchanged. - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: approval-engine podSelector: matchLabels: app.kubernetes.io/name: approval-engine ports: - {protocol: TCP, port: 8080} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-operator-ingress namespace: audit-core spec: podSelector: matchLabels: app.kubernetes.io/name: audit-core policyTypes: [Ingress] ingress: # Operator read path: lookup, dead letters, secret findings, stats. # Namespace-scoped rather than open, and still gated on a credential # carrying may_read — the network rule is the outer of two checks, not the # only one. - from: - namespaceSelector: matchLabels: railiance.io/audit-core-reader: "true" ports: - {protocol: TCP, port: 8080} --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: audit-core-egress namespace: audit-core spec: podSelector: matchLabels: app.kubernetes.io/name: audit-core policyTypes: [Egress] egress: # PostgreSQL custody store. This is the only destination the receiver needs; # it calls no other service. - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: databases ports: - {protocol: TCP, port: 5432} - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - {protocol: UDP, port: 53} - {protocol: TCP, port: 53}