mirror of
https://github.com/wahyd4/home-docker.git
synced 2026-08-09 04:15:52 +10:00
359 lines
10 KiB
Terraform
359 lines
10 KiB
Terraform
# CrowdSec Security Engine Deployment
|
|
# Monitors and protects against malicious traffic on NGINX Ingress
|
|
|
|
resource "kubernetes_namespace" "crowdsec" {
|
|
metadata {
|
|
name = "crowdsec"
|
|
}
|
|
}
|
|
|
|
# PersistentVolume for LAPI config on host path
|
|
resource "kubernetes_persistent_volume" "crowdsec_lapi_config" {
|
|
metadata {
|
|
name = "crowdsec-lapi-config-pv"
|
|
}
|
|
spec {
|
|
capacity = {
|
|
storage = "1Gi"
|
|
}
|
|
access_modes = ["ReadWriteOnce"]
|
|
storage_class_name = "local-path"
|
|
persistent_volume_source {
|
|
host_path {
|
|
path = "/mnt/k8s/crowdsec/lapi-config"
|
|
type = "DirectoryOrCreate"
|
|
}
|
|
}
|
|
node_affinity {
|
|
required {
|
|
node_selector_term {
|
|
match_expressions {
|
|
key = "kubernetes.io/hostname"
|
|
operator = "In"
|
|
values = ["server-3"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# PersistentVolume for LAPI data on host path
|
|
resource "kubernetes_persistent_volume" "crowdsec_lapi_data" {
|
|
metadata {
|
|
name = "crowdsec-lapi-data-pv"
|
|
}
|
|
spec {
|
|
capacity = {
|
|
storage = "2Gi"
|
|
}
|
|
access_modes = ["ReadWriteOnce"]
|
|
storage_class_name = "local-path"
|
|
persistent_volume_source {
|
|
host_path {
|
|
path = "/mnt/k8s/crowdsec/lapi-data"
|
|
type = "DirectoryOrCreate"
|
|
}
|
|
}
|
|
node_affinity {
|
|
required {
|
|
node_selector_term {
|
|
match_expressions {
|
|
key = "kubernetes.io/hostname"
|
|
operator = "In"
|
|
values = ["server-3"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "helm_release" "crowdsec" {
|
|
name = "crowdsec"
|
|
repository = "https://crowdsecurity.github.io/helm-charts"
|
|
chart = "crowdsec"
|
|
version = "0.22.0"
|
|
namespace = kubernetes_namespace.crowdsec.metadata[0].name
|
|
|
|
wait = true
|
|
timeout = 600
|
|
|
|
values = [
|
|
yamlencode({
|
|
container_runtime = "containerd"
|
|
|
|
image = {
|
|
repository = "crowdsecurity/crowdsec"
|
|
tag = "v1.7.6"
|
|
pullPolicy = "IfNotPresent"
|
|
}
|
|
|
|
lapi = {
|
|
enabled = true
|
|
replicas = 1
|
|
|
|
resources = {
|
|
limits = {
|
|
memory = "512Mi"
|
|
cpu = "500m"
|
|
}
|
|
requests = {
|
|
memory = "256Mi"
|
|
cpu = "100m"
|
|
}
|
|
}
|
|
|
|
persistentVolume = {
|
|
config = {
|
|
enabled = true
|
|
accessModes = ["ReadWriteOnce"]
|
|
storageClassName = "local-path"
|
|
size = "1Gi"
|
|
}
|
|
data = {
|
|
enabled = true
|
|
accessModes = ["ReadWriteOnce"]
|
|
storageClassName = "local-path"
|
|
size = "2Gi"
|
|
}
|
|
}
|
|
|
|
metrics = {
|
|
enabled = true
|
|
}
|
|
|
|
env = [
|
|
{
|
|
name = "ENROLL_KEY"
|
|
value = "cmgcsgn14000e02l1xmme5qnm"
|
|
},
|
|
{
|
|
name = "ENROLL_INSTANCE_NAME"
|
|
value = "junv-home-k3s-cluster"
|
|
},
|
|
{
|
|
name = "ENROLL_TAGS"
|
|
value = "junv k3s homelab nginx"
|
|
}
|
|
]
|
|
}
|
|
|
|
agent = {
|
|
enabled = true
|
|
isDeployment = false
|
|
|
|
resources = {
|
|
limits = {
|
|
memory = "512Mi"
|
|
cpu = "500m"
|
|
}
|
|
requests = {
|
|
memory = "256Mi"
|
|
cpu = "100m"
|
|
}
|
|
}
|
|
|
|
hostVarLog = true
|
|
|
|
metrics = {
|
|
enabled = true
|
|
}
|
|
|
|
# Monitor NGINX Ingress Controller logs and SSH logs
|
|
acquisition = [
|
|
{
|
|
namespace = "ingress-nginx"
|
|
podName = "ingress-nginx-controller-*"
|
|
program = "nginx"
|
|
poll_without_inotify = true # Container logs are symlinks, need polling
|
|
}
|
|
]
|
|
|
|
# Additional acquisition for host SSH logs and firewall logs
|
|
additionalAcquisition = [
|
|
{
|
|
source = "file"
|
|
filenames = ["/var/log/auth.log"]
|
|
labels = {
|
|
type = "syslog"
|
|
}
|
|
},
|
|
{
|
|
source = "file"
|
|
filenames = ["/var/log/kern.log", "/var/log/syslog"]
|
|
labels = {
|
|
type = "syslog"
|
|
}
|
|
}
|
|
]
|
|
|
|
# Install NGINX, SSH, and iptables/firewall collections
|
|
env = [
|
|
{
|
|
name = "COLLECTIONS"
|
|
value = "crowdsecurity/nginx crowdsecurity/base-http-scenarios crowdsecurity/linux crowdsecurity/sshd crowdsecurity/iptables crowdsecurity/endlessh"
|
|
}
|
|
]
|
|
|
|
persistentVolume = {
|
|
config = {
|
|
enabled = false
|
|
}
|
|
}
|
|
}
|
|
|
|
config = {
|
|
"config.yaml.local" = <<-EOT
|
|
api:
|
|
server:
|
|
auto_registration:
|
|
enabled: true
|
|
token: "$${REGISTRATION_TOKEN}"
|
|
allowed_ranges:
|
|
- "127.0.0.1/32"
|
|
- "10.0.0.0/8"
|
|
- "172.16.0.0/12"
|
|
- "192.168.0.0/16"
|
|
log_level: info
|
|
listen_uri: 0.0.0.0:8080
|
|
client:
|
|
insecure_skip_verify: false
|
|
common:
|
|
daemonize: false
|
|
log_media: stdout
|
|
log_level: info
|
|
EOT
|
|
|
|
"profiles.yaml.local" = <<-EOT
|
|
name: default_ip_remediation
|
|
filters:
|
|
- Alert.Remediation == true && Alert.GetScope() == "Ip"
|
|
decisions:
|
|
- type: ban
|
|
duration: 24h
|
|
on_success: break
|
|
EOT
|
|
}
|
|
})
|
|
]
|
|
|
|
depends_on = [
|
|
kubernetes_namespace.crowdsec,
|
|
kubernetes_persistent_volume.crowdsec_lapi_config,
|
|
kubernetes_persistent_volume.crowdsec_lapi_data
|
|
]
|
|
}
|
|
|
|
# Wait for CrowdSec to be ready and create bouncer
|
|
resource "null_resource" "crowdsec_bouncer_setup" {
|
|
depends_on = [helm_release.crowdsec]
|
|
|
|
provisioner "local-exec" {
|
|
command = <<-EOT
|
|
echo "Waiting for CrowdSec LAPI to be ready..."
|
|
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=crowdsec,app.kubernetes.io/component=lapi -n crowdsec --timeout=300s
|
|
|
|
echo "Creating NGINX bouncer..."
|
|
BOUNCER_KEY=$(kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli bouncers add nginx-ingress-bouncer -o raw 2>/dev/null || echo "")
|
|
|
|
if [ -z "$BOUNCER_KEY" ]; then
|
|
echo "Bouncer may already exist, retrieving existing key..."
|
|
kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli bouncers list
|
|
else
|
|
echo "Bouncer created successfully!"
|
|
echo "Creating Kubernetes secret with bouncer key..."
|
|
kubectl create secret generic crowdsec-bouncer-tls -n ingress-nginx \
|
|
--from-literal=crowdsec-api=http://crowdsec-service.crowdsec.svc.cluster.local:8080 \
|
|
--from-literal=crowdsec-key="$BOUNCER_KEY" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
echo "Bouncer API Key: $BOUNCER_KEY"
|
|
fi
|
|
|
|
echo ""
|
|
echo "CrowdSec setup complete!"
|
|
echo "To view status: kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli metrics"
|
|
EOT
|
|
}
|
|
|
|
triggers = {
|
|
crowdsec_version = helm_release.crowdsec.version
|
|
}
|
|
}
|
|
|
|
# DISABLED: iptables logging was causing connectivity issues with kubectl
|
|
# The rules were blocking legitimate Kubernetes traffic
|
|
# CrowdSec will still monitor logs without iptables integration
|
|
|
|
# resource "ssh_resource" "iptables_logging" {
|
|
# depends_on = [helm_release.crowdsec]
|
|
#
|
|
# host = local.ssh_host
|
|
# user = local.ssh_user
|
|
# port = local.ssh_port
|
|
# private_key = local.ssh_private_key
|
|
# timeout = "5m"
|
|
#
|
|
# when = "create"
|
|
#
|
|
# commands = [
|
|
# "echo 'Setting up iptables logging for CrowdSec...'",
|
|
#
|
|
# # Create chain for suspicious activity logging
|
|
# "sudo iptables -N CROWDSEC_SUSPICIOUS 2>/dev/null || true",
|
|
# "sudo iptables -F CROWDSEC_SUSPICIOUS 2>/dev/null || true",
|
|
#
|
|
# # IMPORTANT: Exclude local network (192.168.1.0/24) from ALL port scan detection
|
|
# "sudo iptables -I INPUT 1 -s 192.168.1.0/24 -j ACCEPT || true",
|
|
#
|
|
# # Track connection attempts for port scan detection (only for external traffic)
|
|
# "sudo iptables -A INPUT -p tcp -m state --state NEW -m recent --set --name portscan || true",
|
|
#
|
|
# # If more than 10 connection attempts in 60 seconds from external IPs, log it as suspicious
|
|
# "sudo iptables -A INPUT -p tcp -m state --state NEW -m recent --update --seconds 60 --hitcount 10 --name portscan -j CROWDSEC_SUSPICIOUS || true",
|
|
#
|
|
# # Log suspicious activity
|
|
# "sudo iptables -A CROWDSEC_SUSPICIOUS -j LOG --log-prefix 'iptables_SCAN: ' --log-level 4 --log-tcp-options --log-ip-options || true",
|
|
#
|
|
# # Drop the suspicious packets
|
|
# "sudo iptables -A CROWDSEC_SUSPICIOUS -j DROP || true",
|
|
#
|
|
# # Log invalid packets from external sources only (often used in attacks)
|
|
# "sudo iptables -A INPUT -m state --state INVALID -j LOG --log-prefix 'iptables_INVALID: ' --log-level 4 || true",
|
|
# "sudo iptables -A INPUT -m state --state INVALID -j DROP || true",
|
|
#
|
|
# # Install iptables-persistent to save rules
|
|
# "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent 2>/dev/null || true",
|
|
#
|
|
# # Save the rules
|
|
# "sudo mkdir -p /etc/iptables",
|
|
# "sudo iptables-save | sudo tee /etc/iptables/rules.v4 > /dev/null",
|
|
#
|
|
# "echo '✅ iptables logging configured!'",
|
|
# "echo 'Port scans and suspicious activity will now be logged and detected by CrowdSec'"
|
|
# ]
|
|
# }
|
|
|
|
output "crowdsec_info" {
|
|
value = <<-EOT
|
|
CrowdSec deployed successfully!
|
|
|
|
Monitoring:
|
|
- ✅ NGINX Ingress (ingress-nginx namespace)
|
|
- ✅ SSH attempts (port 22422)
|
|
- ✅ Port scans (iptables logging enabled)
|
|
- ✅ System logs
|
|
|
|
Commands:
|
|
- Status: kubectl get pods -n crowdsec
|
|
- Metrics: kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli metrics
|
|
- Decisions: kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli decisions list
|
|
- Bouncers: kubectl exec -n crowdsec deployment/crowdsec-lapi -- cscli bouncers list
|
|
|
|
Storage: /mnt/k8s/crowdsec/ on server-3 (192.168.1.2)
|
|
Web Dashboard: https://app.crowdsec.net
|
|
|
|
Quick view: ./view_crowdsec.sh
|
|
EOT
|
|
}
|