# CrowdSec Firewall Bouncer - nftables enforcement on each node # Blocks malicious IPs before they reach Cilium eBPF processing # Requires: hostNetwork + privileged (nftables management) # Image: community Docker build of cs-firewall-bouncer (no official image exists) # # api_url points at a headless Service (below), not the normal ClusterIP # crowdsec-service. Cilium's socketLB is configured hostNamespaceOnly (see # infrastructure/cilium/values.yaml, needed for Istio ambient compatibility), # which means socket-level Service translation/policy enforcement applies to # host-namespace traffic - and this bouncer runs hostNetwork: true, so it IS # host-namespace traffic. Connecting to a ClusterIP VIP from there gets an # immediate EPERM on connect() (confirmed live 2026-08-17, been broken since # this DaemonSet was first deployed 2026-03-03 - not a regression from any # recent change). A headless Service resolves straight to pod IPs via DNS - # no VIP, nothing for socket-LB to intercept - and connects cleanly. --- apiVersion: v1 kind: Service metadata: name: crowdsec-lapi-headless namespace: crowdsec spec: clusterIP: None selector: k8s-app: crowdsec type: lapi version: v1 ports: - name: lapi port: 8080 protocol: TCP targetPort: 8080 --- apiVersion: v1 kind: ConfigMap metadata: name: crowdsec-firewall-bouncer-config namespace: crowdsec data: crowdsec-firewall-bouncer.yaml: | mode: nftables update_frequency: 10s log_mode: stdout log_level: info api_url: http://crowdsec-lapi-headless.crowdsec.svc:8080/ api_key: ${API_KEY} insecure_skip_verify: false disable_ipv6: false deny_action: DROP deny_log: true deny_log_prefix: "crowdsec: " supported_decisions_types: - ban blacklists_ipv4: crowdsec-blacklists blacklists_ipv6: crowdsec6-blacklists nftables: ipv4: enabled: true set-only: false table: crowdsec chain: crowdsec-chain priority: -10 ipv6: enabled: true set-only: false table: crowdsec6 chain: crowdsec6-chain priority: -10 nftables_hooks: - input - forward prometheus: enabled: true listen_addr: 0.0.0.0 listen_port: 60601 --- apiVersion: apps/v1 kind: DaemonSet metadata: name: crowdsec-firewall-bouncer namespace: crowdsec labels: app: crowdsec-firewall-bouncer spec: selector: matchLabels: app: crowdsec-firewall-bouncer template: metadata: labels: app: crowdsec-firewall-bouncer spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet tolerations: - operator: Exists initContainers: # Render env vars in config template - name: render-config image: docker.io/library/busybox:1.36 securityContext: runAsUser: 10000 runAsGroup: 10000 runAsNonRoot: true allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] seccompProfile: type: RuntimeDefault command: ["/bin/sh", "-c"] args: - | sed "s|\${API_KEY}|${API_KEY}|g" /config-template/crowdsec-firewall-bouncer.yaml > /config/crowdsec-firewall-bouncer.yaml env: - name: API_KEY valueFrom: secretKeyRef: name: crowdsec-bouncer-key key: api-key volumeMounts: - name: config-template mountPath: /config-template - name: config-rendered mountPath: /config containers: - name: bouncer image: ghcr.io/shgew/cs-firewall-bouncer-docker:v0.0.34-patch1 command: - /usr/local/bin/crowdsec-firewall-bouncer - -c - /config/crowdsec-firewall-bouncer.yaml resources: requests: cpu: 10m memory: 32Mi limits: memory: 64Mi securityContext: privileged: true capabilities: add: - NET_ADMIN - NET_RAW volumeMounts: - name: config-rendered mountPath: /config readOnly: true - name: nftables-lock mountPath: /run volumes: - name: config-template configMap: name: crowdsec-firewall-bouncer-config - name: config-rendered emptyDir: {} - name: nftables-lock hostPath: path: /run type: Directory --- apiVersion: v1 kind: Service metadata: name: crowdsec-firewall-bouncer-metrics namespace: crowdsec labels: app: crowdsec-firewall-bouncer spec: selector: app: crowdsec-firewall-bouncer ports: - name: metrics port: 60601 targetPort: 60601 protocol: TCP --- apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: crowdsec-firewall-bouncer namespace: crowdsec labels: app: crowdsec-firewall-bouncer release: kube-prometheus-stack spec: selector: matchLabels: app: crowdsec-firewall-bouncer endpoints: - port: metrics interval: 30s