---
# CrowdSec → NGINX Ingress IP Block Sync
#
# Runs every minute, reads all active CrowdSec ban decisions,
# and updates the NGINX Ingress Controller ConfigMap's block-cidrs field.
# This propagates CrowdSec's automated threat detection into NGINX's global IP blocklist.
# VPN/client IPs in ALLOWLIST below are excluded from the NGINX blocklist.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: crowdsec-nginx-sync
  namespace: crowdsec

---
# Allow the sync job to read CrowdSec LAPI pod exec (to run cscli)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: crowdsec-nginx-sync
rules:
  # Exec into CrowdSec LAPI pod to run cscli
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]
  # Read/patch the NGINX Ingress ConfigMap
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: crowdsec-nginx-sync
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: crowdsec-nginx-sync
subjects:
  - kind: ServiceAccount
    name: crowdsec-nginx-sync
    namespace: crowdsec

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: crowdsec-nginx-sync
  namespace: crowdsec
spec:
  schedule: "* * * * *"        # every minute
  concurrencyPolicy: Forbid    # skip if previous run is still going
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      activeDeadlineSeconds: 55  # must finish before next run
      template:
        spec:
          serviceAccountName: crowdsec-nginx-sync
          restartPolicy: Never
          containers:
            - name: sync
              image: bitnami/kubectl:latest
              command:
                - /bin/sh
                - -c
                - |
                  set -e

                  # Find the CrowdSec LAPI pod
                  LAPI_POD=$(kubectl get pods -n crowdsec \
                    -l "type=lapi" \
                    -o jsonpath='{.items[0].metadata.name}')

                  if [ -z "$LAPI_POD" ]; then
                    echo "ERROR: CrowdSec LAPI pod not found"
                    exit 1
                  fi

                  echo "Using LAPI pod: $LAPI_POD"

                  # Fetch all active ban decisions in raw CSV format:
                  # id,source,ip,reason,action,country,as,events_count,expiration,simulated,alert_id
                  # The ip column has format "Ip:1.2.3.4" or "Range:1.2.3.0/24"
                  RAW=$(kubectl exec -n crowdsec "$LAPI_POD" -- \
                    cscli decisions list -t ban -o raw 2>/dev/null || true)

                  # Skip CSV header, extract column 3, strip the "Ip:" / "Range:" prefix
                  CIDRS=$(echo "$RAW" | \
                    tail -n +2 | \
                    cut -d',' -f3 | \
                    sed 's/^[^:]*://g' | \
                    grep -v '^$' | \
                    tr '\n' ',' | \
                    sed 's/,$//')

                  echo "Active ban count: $(echo "$RAW" | tail -n +2 | grep -c '.' || echo 0)"

                  # Read any manually managed IPs from block-cidrs-manual key in the same ConfigMap.
                  # Edit that key to permanently block IPs that CrowdSec won't remove.
                  MANUAL=$(kubectl get configmap ingress-nginx-controller \
                    -n ingress-nginx \
                    -o jsonpath='{.data.block-cidrs-manual}' 2>/dev/null || true)

                  # VPN/client IPs that should never be written into NGINX block-cidrs.
                  ALLOWLIST="195.86.27.8,14.137.198.99"

                  # Merge CrowdSec bans + manual list, remove allowlisted entries, deduplicate
                  ALL=$(printf '%s,%s' "$CIDRS" "$MANUAL" | \
                    tr ',' '\n' | \
                    grep -v '^$' | \
                    awk -v allowlist="$ALLOWLIST" 'BEGIN { split(allowlist, ips, ","); for (i in ips) allow[ips[i]] = 1 } !allow[$0]' | \
                    sort -u | \
                    tr '\n' ',' | \
                    sed 's/,$//')

                  echo "CrowdSec bans: ${CIDRS:-<none>}"
                  echo "Manual bans:   ${MANUAL:-<none>}"
                  echo "Allowlist:     ${ALLOWLIST:-<none>}"
                  echo "Merged total:  ${ALL:-<none>}"

                  # Patch the NGINX Ingress ConfigMap (JSON merge patch — only updates block-cidrs)
                  kubectl patch configmap ingress-nginx-controller \
                    -n ingress-nginx \
                    --type merge \
                    -p "{\"data\":{\"block-cidrs\":\"${ALL}\"}}"

                  echo "ConfigMap patched successfully"
              resources:
                requests:
                  cpu: 10m
                  memory: 32Mi
                limits:
                  cpu: 100m
                  memory: 64Mi
