diff --git a/README.md b/README.md index bc1ece7..d421745 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,7 @@ Kerno tags every finding with pod, namespace, node, and workload labels. No `cli - Runs with the **minimum capabilities needed** - `CAP_BPF`, `CAP_PERFMON`, `CAP_SYS_PTRACE`, `CAP_NET_ADMIN`, `CAP_DAC_READ_SEARCH` (not `CAP_SYS_ADMIN` for the hot path). - Read-only root filesystem, `ProtectSystem=strict` via systemd on bare metal. - No outbound network calls. AI integration is opt-in and goes through your configured provider only. +- **Opt-in NetworkPolicy**: Limit metrics ingress to Prometheus pods, and allow DNS, K8s API server, and Kubelet egress. (Note: Since Kerno runs with `hostNetwork: true`, standard `NetworkPolicy` resources do not enforce restrictions on it in most mainstream CNIs without host-firewall configuration). See [Helm README](deploy/helm/kerno/README.md). ### Helm values @@ -253,6 +254,9 @@ serviceMonitor: # Prometheus Operator enabled: true interval: 15s +networkPolicy: + enabled: false + nodeSelector: monitoring: "true" ``` diff --git a/deploy/helm/kerno/README.md b/deploy/helm/kerno/README.md new file mode 100644 index 0000000..aea2f85 --- /dev/null +++ b/deploy/helm/kerno/README.md @@ -0,0 +1,19 @@ +# Kerno Helm Chart + +Deploys Kerno as a DaemonSet. + +## Installation + +```bash +helm install kerno ./deploy/helm/kerno -n kerno-system --create-namespace +``` + +## Hardening + +Set `networkPolicy.enabled=true` to enable the NetworkPolicy. + +> [!WARNING] +> Since Kerno runs with `hostNetwork: true`, standard Kubernetes `NetworkPolicy` resources are not enforced on it by most mainstream CNIs (like Cilium or Calico) without host-endpoint or host-firewall configuration. +> +> If `networkPolicy.enabled` is set to `true`, egress to the Kubernetes API server and Kubelet is blocked by default unless their specific IP CIDR blocks are configured via `networkPolicy.k8sApiServer.cidrs` and `networkPolicy.kubelet.cidrs` respectively. + diff --git a/deploy/helm/kerno/templates/networkpolicy.yaml b/deploy/helm/kerno/templates/networkpolicy.yaml new file mode 100644 index 0000000..2537722 --- /dev/null +++ b/deploy/helm/kerno/templates/networkpolicy.yaml @@ -0,0 +1,77 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: kerno + namespace: {{ .Release.Namespace }} + labels: + {{- include "kerno.labels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include "kerno.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + - ports: + - protocol: TCP + port: {{ .Values.prometheus.port }} + {{- if or .Values.networkPolicy.prometheus.namespaceSelector .Values.networkPolicy.prometheus.podSelector }} + from: + {{- if .Values.networkPolicy.prometheus.namespaceSelector }} + - namespaceSelector: + {{- toYaml .Values.networkPolicy.prometheus.namespaceSelector | nindent 12 }} + {{- if .Values.networkPolicy.prometheus.podSelector }} + podSelector: + {{- toYaml .Values.networkPolicy.prometheus.podSelector | nindent 12 }} + {{- end }} + {{- else if .Values.networkPolicy.prometheus.podSelector }} + - podSelector: + {{- toYaml .Values.networkPolicy.prometheus.podSelector | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.additionalIngress }} + {{- toYaml .Values.networkPolicy.additionalIngress | nindent 4 }} + {{- end }} + egress: + - ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + podSelector: + matchLabels: + k8s-app: kube-dns + {{- if .Values.networkPolicy.k8sApiServer.cidrs }} + - ports: + {{- range .Values.networkPolicy.k8sApiServer.ports }} + - protocol: TCP + port: {{ . }} + {{- end }} + to: + {{- range .Values.networkPolicy.k8sApiServer.cidrs }} + - ipBlock: + cidr: {{ . }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.kubelet.cidrs }} + - ports: + {{- range .Values.networkPolicy.kubelet.ports }} + - protocol: TCP + port: {{ . }} + {{- end }} + to: + {{- range .Values.networkPolicy.kubelet.cidrs }} + - ipBlock: + cidr: {{ . }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.additionalEgress }} + {{- toYaml .Values.networkPolicy.additionalEgress | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/helm/kerno/values.yaml b/deploy/helm/kerno/values.yaml index 371ba23..8683c02 100644 --- a/deploy/helm/kerno/values.yaml +++ b/deploy/helm/kerno/values.yaml @@ -120,3 +120,31 @@ securityContext: # Host path prefix — Kerno mounts host paths under /host/ to avoid conflicts. # All pollers read from /host/proc, /host/sys/fs/cgroup, etc. hostPathPrefix: /host + +# NetworkPolicy configuration. +# NOTE: Since Kerno runs with 'hostNetwork: true', standard NetworkPolicies +# do not restrict its traffic in most CNIs without host-firewall configuration. +networkPolicy: + enabled: false + prometheus: + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: monitoring + podSelector: + matchLabels: + app.kubernetes.io/name: prometheus + k8sApiServer: + ports: + - 443 + - 6443 + # Target API server CIDRs. If empty, egress is blocked by default. + cidrs: [] + kubelet: + ports: + - 10250 + - 10255 + # Target Kubelet CIDRs. If empty, egress is blocked by default. + cidrs: [] + additionalIngress: [] + additionalEgress: [] +