mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-09-02 20:28:50 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
976cbb7d1f | ||
|
|
80726df450 |
+11
-9
@@ -15,8 +15,6 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
simpleredis "github.com/maxlerebourg/simpleredis"
|
|
||||||
|
|
||||||
cache "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/cache"
|
cache "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/cache"
|
||||||
configuration "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/configuration"
|
configuration "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/configuration"
|
||||||
ip "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip"
|
ip "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/pkg/ip"
|
||||||
@@ -35,6 +33,7 @@ const (
|
|||||||
|
|
||||||
//nolint:gochecknoglobals
|
//nolint:gochecknoglobals
|
||||||
var (
|
var (
|
||||||
|
isStartup = true
|
||||||
isCrowdsecStreamHealthy = true
|
isCrowdsecStreamHealthy = true
|
||||||
ticker chan bool
|
ticker chan bool
|
||||||
)
|
)
|
||||||
@@ -85,7 +84,7 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
|
|||||||
crowdsecStreamRoute := ""
|
crowdsecStreamRoute := ""
|
||||||
crowdsecHeader := ""
|
crowdsecHeader := ""
|
||||||
if config.CrowdsecMode == configuration.AloneMode {
|
if config.CrowdsecMode == configuration.AloneMode {
|
||||||
config.CrowdsecCapiMachineID, _ = configuration.GetVariable(config, "CrowdsecCapiMachineId")
|
config.CrowdsecCapiMachineID, _ = configuration.GetVariable(config, "CrowdsecCapiMachineID")
|
||||||
config.CrowdsecCapiPassword, _ = configuration.GetVariable(config, "CrowdsecCapiPassword")
|
config.CrowdsecCapiPassword, _ = configuration.GetVariable(config, "CrowdsecCapiPassword")
|
||||||
config.CrowdsecLapiHost = "api.crowdsec.net"
|
config.CrowdsecLapiHost = "api.crowdsec.net"
|
||||||
config.CrowdsecLapiScheme = "https"
|
config.CrowdsecLapiScheme = "https"
|
||||||
@@ -155,7 +154,8 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
|
|||||||
ticker = startTicker(config, func() {
|
ticker = startTicker(config, func() {
|
||||||
handleStreamCache(bouncer)
|
handleStreamCache(bouncer)
|
||||||
})
|
})
|
||||||
go handleStreamCache(bouncer)
|
handleStreamCache(bouncer)
|
||||||
|
isStartup = false
|
||||||
}
|
}
|
||||||
logger.Debug(fmt.Sprintf("New initialized mode:%s", config.CrowdsecMode))
|
logger.Debug(fmt.Sprintf("New initialized mode:%s", config.CrowdsecMode))
|
||||||
|
|
||||||
@@ -193,10 +193,12 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
// TODO This should be simplified
|
// TODO This should be simplified
|
||||||
if bouncer.crowdsecMode != configuration.NoneMode {
|
if bouncer.crowdsecMode != configuration.NoneMode {
|
||||||
isBanned, erro := bouncer.cacheClient.GetDecision(remoteIP)
|
isBanned, cacheErr := bouncer.cacheClient.GetDecision(remoteIP)
|
||||||
if erro != nil {
|
if cacheErr != nil {
|
||||||
logger.Debug(fmt.Sprintf("ServeHTTP:getDecision ip:%s isBanned:true %s", remoteIP, erro.Error()))
|
errString := cacheErr.Error()
|
||||||
if erro.Error() == simpleredis.RedisUnreachable {
|
logger.Debug(fmt.Sprintf("ServeHTTP:getDecision ip:%s isBanned:false %s", remoteIP, errString))
|
||||||
|
if errString != cache.CacheMiss {
|
||||||
|
logger.Error(fmt.Sprintf("ServeHTTP:getDecision ip:%s %s", remoteIP, errString))
|
||||||
rw.WriteHeader(http.StatusForbidden)
|
rw.WriteHeader(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -361,7 +363,7 @@ func handleStreamCache(bouncer *Bouncer) {
|
|||||||
Scheme: bouncer.crowdsecScheme,
|
Scheme: bouncer.crowdsecScheme,
|
||||||
Host: bouncer.crowdsecHost,
|
Host: bouncer.crowdsecHost,
|
||||||
Path: bouncer.crowdsecStreamRoute,
|
Path: bouncer.crowdsecStreamRoute,
|
||||||
RawQuery: fmt.Sprintf("startup=%t", !isCrowdsecStreamHealthy),
|
RawQuery: fmt.Sprintf("startup=%t", !isCrowdsecStreamHealthy || isStartup),
|
||||||
}
|
}
|
||||||
body, err := crowdsecQuery(bouncer, streamRouteURL.String(), false)
|
body, err := crowdsecQuery(bouncer, streamRouteURL.String(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ These CAPI credentials must be set in your docker-compose.yml or in your config
|
|||||||
...
|
...
|
||||||
whoami:
|
whoami:
|
||||||
labels:
|
labels:
|
||||||
|
- "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true"
|
||||||
|
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecMode=alone"
|
||||||
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecCapiMachineId=LOGIN"
|
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecCapiMachineId=LOGIN"
|
||||||
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecCapiPassword=PASSWORD"
|
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecCapiPassword=PASSWORD"
|
||||||
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapiscenarios=crowdsecurity/http-generic-bf,crowdsecurity/http-xss-probing,..."
|
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecCapiScenarios=crowdsecurity/http-generic-bf,crowdsecurity/http-xss-probing,..."
|
||||||
- "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then run all the containers:
|
You can then run all the containers:
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: "traefik:v2.9.6"
|
||||||
|
container_name: "traefik"
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
# - "--log.level=DEBUG"
|
||||||
|
- "--accesslog"
|
||||||
|
- "--accesslog.filepath=/var/log/traefik/access.log"
|
||||||
|
- "--api.insecure=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
|
||||||
|
- "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
|
||||||
|
- "--experimental.plugins.bouncer.version=v1.1.7"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
ports:
|
||||||
|
- 80:80
|
||||||
|
- 8080:8080
|
||||||
|
|
||||||
|
whoami-foo:
|
||||||
|
image: traefik/whoami
|
||||||
|
container_name: "simple-service-foo"
|
||||||
|
restart: unless-stopped
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.router-foo.rule=Path(`/foo`)"
|
||||||
|
- "traefik.http.routers.router-foo.entrypoints=web"
|
||||||
|
- "traefik.http.routers.router-foo.middlewares=crowdsec-foo@docker"
|
||||||
|
- "traefik.http.services.service-foo.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.enabled=true"
|
||||||
|
# - "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.loglevel=DEBUG"
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.crowdsecmode=alone"
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.crowdseclapikey=40796d93c2958f9e58345514e67740e5"
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.CrowdsecCapiMachineId=logincacacalfkrjebfreifgzfblezgyfoerxsqxsqxsqxsr"
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.CrowdsecCapiPassword=Password2"
|
||||||
|
- "traefik.http.middlewares.crowdsec-foo.plugin.bouncer.crowdseccapiscenarios=crowdsecurity/sshd,crowdsecurity/asterisk_bf,crowdsecurity/asterisk_user_enum,crowdsecurity/base-http-scenarios"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
logs-local:
|
||||||
Vendored
+7
-1
@@ -16,6 +16,9 @@ const (
|
|||||||
cacheNoBannedValue = "f"
|
cacheNoBannedValue = "f"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CacheMiss error string when cache is miss.
|
||||||
|
const CacheMiss = "cache:miss"
|
||||||
|
|
||||||
//nolint:gochecknoglobals
|
//nolint:gochecknoglobals
|
||||||
var (
|
var (
|
||||||
redis simpleredis.SimpleRedis
|
redis simpleredis.SimpleRedis
|
||||||
@@ -30,7 +33,7 @@ func (localCache) getDecision(clientIP string) (bool, error) {
|
|||||||
if isCached && isValid && len(bannedString) > 0 {
|
if isCached && isValid && len(bannedString) > 0 {
|
||||||
return bannedString == cacheBannedValue, nil
|
return bannedString == cacheBannedValue, nil
|
||||||
}
|
}
|
||||||
return false, fmt.Errorf("cache:miss")
|
return false, fmt.Errorf(CacheMiss)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (localCache) setDecision(clientIP string, value string, duration int64) {
|
func (localCache) setDecision(clientIP string, value string, duration int64) {
|
||||||
@@ -49,6 +52,9 @@ func (redisCache) getDecision(clientIP string) (bool, error) {
|
|||||||
if err == nil && len(bannedString) > 0 {
|
if err == nil && len(bannedString) > 0 {
|
||||||
return bannedString == cacheBannedValue, nil
|
return bannedString == cacheBannedValue, nil
|
||||||
}
|
}
|
||||||
|
if err.Error() == simpleredis.RedisMiss {
|
||||||
|
return false, fmt.Errorf(CacheMiss)
|
||||||
|
}
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func ValidateParams(config *Config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.CrowdsecMode == AloneMode {
|
if config.CrowdsecMode == AloneMode {
|
||||||
if _, err := GetVariable(config, "CrowdsecCapiMachineId"); err != nil {
|
if _, err := GetVariable(config, "CrowdsecCapiMachineID"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := GetVariable(config, "CrowdsecCapiPassword"); err != nil {
|
if _, err := GetVariable(config, "CrowdsecCapiPassword"); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user