A working version to block intruderce into warpgate
compose.yml
services:
warpgate:
container_name: warpgate
image: ghcr.io/warp-tech/warpgate
ports:
- 2222:2222
- 127.0.0.1:8888:8888
volumes:
- ./data:/data:Z
- ./sockets:/var/run
stdin_open: true
tty: true
restart: always
environment:
- WARPGATE__WEB__TRUST_PROXY_HEADERS=true
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
vector:
image: timberio/vector:latest-alpine
container_name: vector
restart: unless-stopped
depends_on:
- warpgate
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./vector.yaml:/etc/vector/vector.yaml:ro
- /var/log/warpgate:/var/log/warpgate
command: ["--config", "/etc/vector/vector.yaml"]
vector.yaml
sources:
warpgate:
type: docker_logs
include_containers:
- warpgate
transforms:
to_fail2ban:
type: remap
inputs:
- warpgate
source: |
raw = string!(.message)
# ANSI Escape Codes entfernen (falls vorhanden)
msg = replace(raw, r'\x1b\[[0-9;]*m', "")
# --- 1) HTTP Login failed (401) ---
is_http_fail =
contains(msg, "WARN HTTP:") &&
contains(msg, "/@warpgate/api/auth/login") &&
contains(msg, "status=401") &&
contains(msg, "client_ip")
# --- 2) SSH Auth failed (Credentials/User/Password) ---
# Beispiel von dir:
# "ERROR SSH: Failed to verify credentials ... client_ip=::ffff:222.138.251.223"
is_ssh_fail =
contains(msg, "ERROR SSH:") &&
contains(msg, "Failed to verify credentials") &&
contains(msg, "client_ip")
if !(is_http_fail || is_ssh_fail) {
abort
}
# Zeitstempel robust
ts = format_timestamp!(now(), "%Y-%m-%dT%H:%M:%SZ")
# IP extrahieren
parsed = parse_regex!(msg, r'client_ip\s*=\s*(?P[0-9a-fA-F\.:]+)')
ip = parsed.ip
# IPv4-mapped IPv6 (::ffff:1.2.3.4) normalisieren -> 1.2.3.4
ip = replace(ip, r'^::ffff:', "")
# Ausgabezeile für fail2ban (einheitlich)
if is_http_fail {
.message = ts + " warpgate login failed (http) ip=" + ip
} else {
.message = ts + " warpgate login failed (ssh) ip=" + ip
}
sinks:
fail2ban_file:
type: file
inputs:
- to_fail2ban
path: "/var/log/warpgate/auth.log"
encoding:
codec: text
/etc/fail2ban/filter.d/warpgate.conf
[Definition] datepattern = ^%%Y-%%m-%%dT%%H:%%M:%%SZ failregex = ^.*warpgate login failed.* ip=\s*$ ignoreregex =
/etc/fail2ban/jail.d/warpgate.conf
[warpgate] enabled = true filter = warpgate logpath = /var/log/warpgate/auth.log maxretry = 5 findtime = 300 bantime = 900 banaction = iptables-docker-allports
/etc/fail2ban/action.d/iptables-docker-allports.conf
[Definition] # IPv4 actionstart = iptables -N f2b-|| true iptables -C DOCKER-USER -j f2b- || iptables -I DOCKER-USER -j f2b- iptables -A f2b- -j RETURN actionstop = iptables -D DOCKER-USER -j f2b- || true iptables -F f2b- || true iptables -X f2b- || true actioncheck = iptables -n -L DOCKER-USER | grep -q f2b- actionban = iptables -I f2b- 1 -s -j DROP actionunban = iptables -D f2b- -s -j DROP # IPv6 actionstart += ip6tables -N f2b- || true ip6tables -C DOCKER-USER -j f2b- || ip6tables -I DOCKER-USER -j f2b- ip6tables -A f2b- -j RETURN actionstop += ip6tables -D DOCKER-USER -j f2b- || true ip6tables -F f2b- || true ip6tables -X f2b- || true actioncheck += ip6tables -n -L DOCKER-USER | grep -q f2b- actionban += ip6tables -I f2b- 1 -s -j DROP actionunban += ip6tables -D f2b- -s -j DROP
fail2ban-regex /var/log/warpgate/auth.log /etc/fail2ban/filter.d/warpgate.conf
systemctl restart fail2ban
fail2ban-client status warpgate