Traefik & Crowdsec - Reverse Proxy Stack
Reverse Proxy Stack
- 🌐 Traefik Reverse Proxy
- 👮 Crowdsec Behaviour detection and banning system
- 😃 Traefik Crowdsec Bouncer Links Traefik and Crowdsec
Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. it automatically discovers the right configuration for your services. The magic happens when Traefik inspects your infrastructure, where it finds relevant information and discovers which service serves which request.
I don’t currently have Crowdsec implemented due to some issues, It will be returning soon.
CrowdSec is a free, modern & collaborative behavior detection engine, coupled with a global IP reputation network. CrowdSec is engineered for modern Cloud / Containers / VM-based infrastructures (by decoupling detection and remediation). Once detected you can remedy threats with various bouncers (firewall block, nginx http 403, Captchas, etc.) while the aggressive IP can be sent to CrowdSec for curation before being shared among all users to further improve everyone’s security.
Traefik Crowdsec Bouncer is a http service to verify requests and bounce them according to decisions made by CrowdSec by parsing traefik logs
Kubenetes Helm Chart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
globalArguments:
- "--global.sendanonymoususage=false"
- "--global.checknewversion=false"
additionalArguments:
- "--serversTransport.insecureSkipVerify=true"
- "--log.level=DEBUG"
- "--accesslog=true"
- "--providers.file.directory=/providers"
- "--providers.file.watch=true"
deployment:
enabled: true
replicas: 3
annotations: {}
podAnnotations: {}
additionalContainers: []
initContainers: []
additionalVolumes:
- name: traefik
persistentVolumeClaim:
claimName: traefik
- name: traefik-providers
configMap:
name: traefik-providers
additionalVolumeMounts:
- name: traefik
mountPath: /var/log/traefik
subPath: "log"
- name: traefik-providers
mountPath: /providers
logs:
access:
enabled: true
filePath: "/var/log/traefik/access.log"
ports:
web:
redirectTo:
port: websecure
priority: 10
websecure:
tls:
enabled: true
ingressRoute:
dashboard:
enabled: false
providers:
kubernetesCRD:
enabled: true
ingressClass: traefik-external
allowExternalNameServices: true
allowCrossNamespace: true
kubernetesIngress:
enabled: true
allowExternalNameServices: true
publishedService:
enabled: false
rbac:
enabled: true
service:
enabled: true
type: LoadBalancer
annotations: {}
labels: {}
spec:
loadBalancerIP: 10.0.10.250 # this should be an IP in the MetalLB range
loadBalancerSourceRanges: []
externalIPs: []
nodeSelector:
worker: 'true'
Kubernetes Manifest (Authentik Middleware)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: authentik
namespace: authentik
spec:
forwardAuth:
address: http://authentik-server.authentik:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
Kubernetes Manifest (Dashboard Ingress)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: default
annotations:
kubernetes.io/ingress.class: traefik-external
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.f9.casa`)
kind: Rule
middlewares:
- name: authentik
namespace: authentik
services:
- name: api@internal
namespace: traefik
kind: TraefikService
tls:
secretName: f9-casa-tls
Docker Compose
I use port mode “host” so i can get the correct IP Address for Crowdsec, due to this i force the container to node 1 I also use 2 different entry points, http/https and web/websecure, http/https is internal only, web/websecure is port forwarded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
version: '3.9'
services:
traefik:
image: traefik:v2.11.0
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 81
published: 81
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 444
published: 444
protocol: tcp
mode: host
environment:
CF_DNS_API_TOKEN: [REDACTED]
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.f9.casa`)
- traefik.http.routers.traefik.entrypoints=https
- traefik.http.routers.traefik.tls.certresolver=letsencrypt
- traefik.http.routers.traefik.service=api@internal
- traefik.http.routers.traefik.middlewares=strip
- traefik.http.middlewares.strip.stripprefix.prefixes=/traefik
- traefik.http.services.dummy-svc.loadbalancer.server.port=9999
- "traefik.http.routers.traefik.middlewares=authentik@docker"
- homepage.group=Networking
- homepage.name=Traefik
- homepage.icon=traefik.png
- homepage.href=https://traefik.f9.casa
- homepage.description=Reverse Proxy
- homepage.siteMonitor=http://traefik:8080/ping
- homepage.widget.type=traefik
- homepage.widget.url=http://traefik:8080
mode: replicated
placement:
constraints:
# Make the traefik service run only on the node with this label
# as the node with it has the volume for the certificates
- node.labels.traefik == true
update_config:
order: stop-first
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
# Make sure the volume folder is created
- /srv/cephfs/docker/appdata/traefik/acme.json:/letsencrypt/acme.json
- /srv/cephfs/docker/appdata/traefik/providers:/providers
- /srv/cephfs/docker/appdata/traefik/logs:/var/log/traefik
command:
# Tell Traefik to discover containers using the Docker API
- --providers.docker
- --providers.docker.network=traefik-public
- --providers.docker.exposedbydefault=false
- --providers.docker.swarmmode
- --providers.file.directory=/providers
- --providers.file.watch=true
# Enable the Trafik dashboard
- --api=true
- --api.insecure=true
- --api.dashboard=true
- --ping=true
# Disable Backend Cert Verification
- --serversTransport.insecureSkipVerify=true
# Set up LetsEncrypt
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.letsencrypt.acme.email=scottleeallen@gmail.com
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
# !IMPORTANT - COMMENT OUT THE FOLLOWING LINE IN PRODUCTION!
#- --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
# Set up an insecure PUBLIC listener that redirects all traffic to TLS
- --entrypoints.web.address=:81
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
- --entrypoints.websecure.address=:444
# Set up an insecure PRIVATE listener that redirects all traffic to TLS
- --entrypoints.http.address=:80
- --entrypoints.http.http.redirections.entrypoint.to=https
- --entrypoints.http.http.redirections.entrypoint.scheme=https
- --entrypoints.https.address=:443
# Set up the TLS configuration for our PUBLIC websecure listener
- --entrypoints.websecure.http.tls=true
- --entrypoints.websecure.http.tls.certResolver=letsencrypt
- --entrypoints.websecure.http.tls.domains[0].main=f9.casa
- --entrypoints.websecure.http.tls.domains[0].sans=*.f9.casa
- --entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
# Set up the TLS configuration for our PRIVATE websecure listener
- --entrypoints.https.http.tls=true
- --entrypoints.https.http.tls.certResolver=letsencrypt
- --entrypoints.https.http.tls.domains[0].main=f9.casa
- --entrypoints.https.http.tls.domains[0].sans=*.f9.casa
# # Set up the DNS TCP/UDP configuration for our dns-xxx listener
# - --entryPoints.dns-udp.address=:53/udp
# - --entryPoints.dns-tcp.address=:53/tcp
- --log.level=DEBUG
- --accesslog=true
- --accesslog.filepath=/var/log/traefik/access.log
- --entrypoints.http.http.middlewares=crowdsec-bouncer@file
- --entrypoints.https.http.middlewares=crowdsec-bouncer@file
- --entrypoints.web.http.middlewares=crowdsec-bouncer@file
- --entrypoints.websecure.http.middlewares=crowdsec-bouncer@file
networks:
# Use the public network created to be shared between Traefik and
# any other service that needs to be publicly available with HTTPS
- traefik-public
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
environment:
- GID=1000
- COLLECTIONS=crowdsecurity/linux crowdsecurity/traefik
volumes:
- /srv/cephfs/docker/appdata/crowdsec:/etc/crowdsec
- /srv/cephfs/docker/appdata/traefik/logs:/var/log/traefik/:ro
networks:
- traefik-public
crowdsec-bouncer:
image: fbonalair/traefik-crowdsec-bouncer
container_name: bouncer-traefik
hostname: bouncer-traefik
environment:
- CROWDSEC_BOUNCER_API_KEY=[REDACTED]
- CROWDSEC_AGENT_HOST=crowdsec:8080
- GIN_MODE=release
networks:
- traefik-public
networks:
traefik-public:
external: true
Docker Configuration
crowdsec/acquis.yaml
1
2
3
4
filenames:
- /var/log/traefik/*
labels:
type: traefik
crowdsec/config.yaml - PostegreSQL configuration
1
2
3
4
5
6
7
8
db_config:
log_level: info
type: postgres
user: crowdsec
password: "[REDACTED]"
db_name: crowdsec
host: postgresql
port: 5432