CrowdSec IPS Pod Scheduling คืออะไร
CrowdSec เป็น open source Intrusion Prevention System (IPS) ที่ใช้ crowdsourced threat intelligence ในการตรวจจับและบล็อกการโจมตี ทำงานคล้าย Fail2Ban แต่มี community-driven blocklists และรองรับ distributed architecture Pod Scheduling คือกระบวนการจัดสรร pods ไปยัง nodes ใน Kubernetes cluster การรวม CrowdSec กับ Kubernetes pod scheduling ช่วยให้ deploy security agents อย่างมีประสิทธิภาพ กระจาย IPS ไปทุก node และจัดการ resources อย่างเหมาะสม
CrowdSec Architecture บน Kubernetes
# crowdsec_arch.py — CrowdSec on Kubernetes
import json
class CrowdSecK8sArch:
COMPONENTS = {
"agent": {
"name": "CrowdSec Agent (Log Processor)",
"role": "อ่าน logs, ตรวจจับ attacks, ส่ง decisions",
"deployment": "DaemonSet (ทุก node)",
"resources": "CPU: 100m-500m, RAM: 128Mi-512Mi",
},
"lapi": {
"name": "LAPI (Local API)",
"role": "Central API สำหรับ decisions, alerts, blocklists",
"deployment": "Deployment (1-3 replicas)",
"resources": "CPU: 200m-1000m, RAM: 256Mi-1Gi",
},
"bouncer": {
"name": "Bouncer (Enforcement)",
"role": "บล็อก traffic ตาม decisions จาก LAPI",
"deployment": "DaemonSet หรือ Sidecar",
"types": "Nginx bouncer, Traefik bouncer, Firewall bouncer",
},
"cscli": {
"name": "cscli (CLI Tool)",
"role": "จัดการ CrowdSec: ดู decisions, alerts, metrics",
"deployment": "ใช้ผ่าน kubectl exec",
},
}
ARCHITECTURE = """
[Internet Traffic]
↓
[Ingress (Nginx/Traefik)]
↓
[CrowdSec Bouncer] ←── block/allow ──→ [LAPI]
↓ ↑
[Application Pods] [CrowdSec Agents]
↑
[Node Logs]
↑
[Community Blocklists]
"""
def show_components(self):
print("=== CrowdSec K8s Components ===\n")
for key, comp in self.COMPONENTS.items():
print(f"[{comp['name']}]")
print(f" Role: {comp['role']}")
print(f" Deploy: {comp['deployment']}")
print()
def show_architecture(self):
print("=== Architecture ===")
print(self.ARCHITECTURE)
arch = CrowdSecK8sArch()
arch.show_components()
arch.show_architecture()
Pod Scheduling Strategies
# scheduling.py — Pod scheduling for CrowdSec
import json
class PodScheduling:
DAEMONSET = """
# crowdsec-agent-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: crowdsec-agent
namespace: crowdsec
spec:
selector:
matchLabels:
app: crowdsec-agent
template:
metadata:
labels:
app: crowdsec-agent
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
- key: node-role.kubernetes.io/master
effect: NoSchedule
nodeSelector:
kubernetes.io/os: linux
containers:
- name: crowdsec
image: crowdsecurity/crowdsec:latest
env:
- name: COLLECTIONS
value: "crowdsecurity/linux crowdsecurity/nginx crowdsecurity/k8s-audit"
- name: CROWDSEC_LAPI_URL
value: "http://crowdsec-lapi:8080"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
"""
AFFINITY = """
# LAPI with anti-affinity (spread across nodes)
apiVersion: apps/v1
kind: Deployment
metadata:
name: crowdsec-lapi
namespace: crowdsec
spec:
replicas: 3
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: crowdsec-lapi
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: crowdsec-lapi
"""
SCHEDULING_TYPES = {
"daemonset": {"name": "DaemonSet", "use": "Agent ทุก node", "guarantee": "1 pod/node"},
"nodeSelector": {"name": "NodeSelector", "use": "เลือก nodes เฉพาะ", "guarantee": "Label match"},
"affinity": {"name": "Node/Pod Affinity", "use": "กระจาย LAPI, co-locate bouncer", "guarantee": "Preferred/Required"},
"tolerations": {"name": "Tolerations", "use": "Agent บน control-plane nodes", "guarantee": "Override taints"},
"topology_spread": {"name": "TopologySpreadConstraints", "use": "กระจายข้าม zones", "guarantee": "Max skew"},
}
def show_daemonset(self):
print("=== DaemonSet Config ===")
print(self.DAEMONSET[:500])
def show_scheduling(self):
print(f"\n=== Scheduling Strategies ===")
for key, s in self.SCHEDULING_TYPES.items():
print(f" [{s['name']}] {s['use']} → {s['guarantee']}")
sched = PodScheduling()
sched.show_daemonset()
sched.show_scheduling()
Helm Installation
# helm_install.py — CrowdSec Helm chart
import json
class HelmInstall:
COMMANDS = """
# Add CrowdSec Helm repo
helm repo add crowdsec https://crowdsecurity.github.io/helm-charts
helm repo update
# Install CrowdSec
helm install crowdsec crowdsec/crowdsec \\
--namespace crowdsec --create-namespace \\
--set agent.acquisition[0].namespace=ingress-nginx \\
--set agent.acquisition[0].podName=ingress-nginx-* \\
--set lapi.replicas=2 \\
--set lapi.persistentVolume.enabled=true \\
--set agent.tolerations[0].key=node-role.kubernetes.io/control-plane \\
--set agent.tolerations[0].effect=NoSchedule
# Verify
kubectl get pods -n crowdsec
kubectl logs -n crowdsec daemonset/crowdsec-agent
"""
VALUES = """
# values.yaml — Custom Helm values
lapi:
replicas: 2
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
persistentVolume:
enabled: true
size: 5Gi
agent:
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
resources:
requests:
cpu: 100m
memory: 128Mi
env:
- name: COLLECTIONS
value: "crowdsecurity/linux crowdsecurity/nginx crowdsecurity/k8s-audit"
acquisition:
- namespace: ingress-nginx
podName: "ingress-nginx-controller-*"
program: nginx
- namespace: default
podName: "*"
program: syslog
"""
def show_commands(self):
print("=== Helm Installation ===")
print(self.COMMANDS[:400])
def show_values(self):
print(f"\n=== Custom Values ===")
print(self.VALUES[:500])
helm = HelmInstall()
helm.show_commands()
helm.show_values()
Monitoring & Alerts
# monitoring.py — CrowdSec monitoring
import json
import random
class CrowdSecMonitoring:
def dashboard(self):
print("=== CrowdSec Dashboard ===\n")
metrics = {
"Total decisions (blocks)": random.randint(500, 5000),
"Active ban IPs": random.randint(50, 500),
"Alerts today": random.randint(10, 100),
"Top scenario": "crowdsecurity/http-bad-user-agent",
"Community blocklist IPs": f"{random.randint(50, 200)}K",
"Agents connected": random.randint(3, 10),
}
for m, v in metrics.items():
print(f" {m}: {v}")
def top_attacks(self):
print(f"\n=== Top Attack Scenarios ===")
scenarios = [
{"name": "http-bad-user-agent", "count": random.randint(100, 500), "action": "ban 4h"},
{"name": "http-probing", "count": random.randint(50, 300), "action": "ban 4h"},
{"name": "ssh-bf", "count": random.randint(20, 100), "action": "ban 24h"},
{"name": "http-crawl-non-statics", "count": random.randint(30, 200), "action": "ban 1h"},
{"name": "http-sqli-probing", "count": random.randint(10, 80), "action": "ban 24h"},
]
for s in scenarios:
print(f" [{s['count']:>4}] {s['name']} → {s['action']}")
def cscli_commands(self):
print(f"\n=== cscli Commands ===")
cmds = [
"cscli decisions list # ดู active decisions",
"cscli alerts list # ดู alerts",
"cscli metrics # ดู metrics",
"cscli bouncers list # ดู connected bouncers",
"cscli hub list # ดู installed collections",
"cscli decisions add --ip 1.2.3.4 --duration 24h # Manual ban",
]
for cmd in cmds:
print(f" $ {cmd}")
mon = CrowdSecMonitoring()
mon.dashboard()
mon.top_attacks()
mon.cscli_commands()
Bouncer Configuration
# bouncer.py — CrowdSec bouncer setup
import json
class BouncerSetup:
NGINX_BOUNCER = """
# Nginx Ingress Bouncer
# Install via Helm
helm install crowdsec-bouncer crowdsec/crowdsec-bouncer-nginx \\
--namespace crowdsec \\
--set config.crowdsecLapiUrl=http://crowdsec-lapi:8080 \\
--set config.crowdsecLapiKey=
# Or as annotation on Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/lua-resty-waf: "active"
"""
TRAEFIK_BOUNCER = """
# Traefik Bouncer (Middleware)
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: crowdsec-bouncer
namespace: crowdsec
spec:
plugin:
crowdsec-bouncer:
crowdsecLapiUrl: http://crowdsec-lapi:8080
crowdsecLapiKey: ""
updateIntervalSeconds: 15
"""
def show_nginx(self):
print("=== Nginx Bouncer ===")
print(self.NGINX_BOUNCER[:400])
def show_traefik(self):
print(f"\n=== Traefik Bouncer ===")
print(self.TRAEFIK_BOUNCER[:300])
bouncer = BouncerSetup()
bouncer.show_nginx()
bouncer.show_traefik()
FAQ - คำถามที่พบบ่อย
Q: CrowdSec กับ Fail2Ban อันไหนดีกว่า?
A: CrowdSec: community blocklists, multi-server, API-driven, Kubernetes-native Fail2Ban: simpler, single server, ไม่มี community sharing ใช้ CrowdSec: production, multi-server, Kubernetes ใช้ Fail2Ban: single VPS, simple setup CrowdSec มี Fail2Ban-compatible scenarios ใช้ migrate ได้ง่าย
Q: ทำไมต้องใช้ DaemonSet สำหรับ agent?
A: DaemonSet รับประกันว่า agent รันบนทุก node ทุก node มี logs ที่ต้อง monitor ถ้าใช้ Deployment อาจมี nodes ที่ไม่มี agent → blind spot ใช้ tolerations เพื่อรันบน control-plane nodes ด้วย
Q: CrowdSec ใช้ resources มากไหม?
A: Agent: 100-500m CPU, 128-512Mi RAM ต่อ node LAPI: 200m-1G CPU, 256Mi-1Gi RAM (ขึ้นอยู่กับ decisions) Bouncer: minimal (แค่ query LAPI) รวม: น้อยกว่า commercial IPS/WAF มาก
Q: Community blocklist ปลอดภัยไหม?
A: ปลอดภัย CrowdSec ใช้ consensus mechanism: IP ต้องถูก report จากหลาย sources False positive rate ต่ำ (< 0.1%) สามารถ whitelist IPs ที่ต้องการได้ ใช้ร่วมกับ local decisions สำหรับ defense-in-depth
