Merge pull request #13 from maxlerebourg/fixMax

 fix loop
This commit is contained in:
maxlerebourg
2022-10-01 19:33:09 +02:00
committed by GitHub
5 changed files with 63 additions and 43 deletions
+4
View File
@@ -1,2 +1,6 @@
.idea/ .idea/
.DS_Store .DS_Store
config
db
logs
docker-compose.dev.yml
+1 -1
View File
@@ -1,4 +1,4 @@
filenames: filenames:
- /var/log/traefik/*.log - /var/log/traefik/access.log
labels: labels:
type: traefik type: traefik
+26 -22
View File
@@ -116,14 +116,17 @@ func New(ctx context.Context, next http.Handler, config *Config, name string) (h
}, },
cache: ttl_map.New(), cache: ttl_map.New(),
} }
// if we are on a stream mode, we fetch in a go routine every minute the new decisions. if config.CrowdsecMode == streamMode || config.CrowdsecMode == aloneMode {
if config.CrowdsecMode == streamMode { if config.CrowdsecMode == aloneMode {
go handleStreamCache(bouncer, true)
} else if config.CrowdsecMode == aloneMode {
getToken(bouncer) getToken(bouncer)
time.AfterFunc(10*time.Second, func() { }
handleStreamCache(bouncer, false) ticker := time.NewTicker(time.Duration(config.UpdateIntervalSeconds) * time.Second)
}) go func() {
go handleStreamCache(bouncer)
for range ticker.C {
go handleStreamCache(bouncer)
}
}()
} }
return bouncer, nil return bouncer, nil
} }
@@ -138,7 +141,7 @@ func (a *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// TODO Make sur remote address does not include the port. // TODO Make sur remote address does not include the port.
remoteHost, _, err := net.SplitHostPort(req.RemoteAddr) remoteHost, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil { if err != nil {
log.Printf("failed to extract ip from remote address: %v", err) logger(fmt.Sprintf("failed to extract ip from remote address: %v", err))
a.next.ServeHTTP(rw, req) a.next.ServeHTTP(rw, req)
return return
} }
@@ -195,6 +198,10 @@ type Login struct {
Expire string `json:"expire"` Expire string `json:"expire"`
} }
func logger(str string) {
log.Printf("Crowdsec Bouncer Traefik Plugin - %s", str)
}
func contains(source []string, target string) bool { func contains(source []string, target string) bool {
for _, a := range source { for _, a := range source {
if a == target { if a == target {
@@ -217,7 +224,7 @@ func getDecision(cache *ttl_map.Heap, clientIP string) (bool, error) {
func setDecision(cache *ttl_map.Heap, clientIP string, isBanned bool, duration int64) { func setDecision(cache *ttl_map.Heap, clientIP string, isBanned bool, duration int64) {
if isBanned { if isBanned {
log.Printf("%v banned", clientIP) logger(fmt.Sprintf("%v banned", clientIP))
cache.Set(clientIP, cacheBannedValue, duration) cache.Set(clientIP, cacheBannedValue, duration)
} else { } else {
cache.Set(clientIP, cacheNoBannedValue, duration) cache.Set(clientIP, cacheNoBannedValue, duration)
@@ -245,7 +252,7 @@ func handleNoStreamCache(a *Bouncer, rw http.ResponseWriter, req *http.Request,
var decisions []Decision var decisions []Decision
err := json.Unmarshal(body, &decisions) err := json.Unmarshal(body, &decisions)
if err != nil { if err != nil {
log.Printf("failed to parse body: %s", err) logger(fmt.Sprintf("failed to parse body: %s", err))
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
return return
} }
@@ -259,24 +266,21 @@ func handleNoStreamCache(a *Bouncer, rw http.ResponseWriter, req *http.Request,
rw.WriteHeader(http.StatusForbidden) rw.WriteHeader(http.StatusForbidden)
duration, err := time.ParseDuration(decisions[0].Duration) duration, err := time.ParseDuration(decisions[0].Duration)
if err != nil { if err != nil {
log.Printf("failed to parse duration: %s", err) logger(fmt.Sprintf("failed to parse duration: %s", err))
return return
} }
setDecision(a.cache, remoteHost, true, int64(duration.Seconds())) setDecision(a.cache, remoteHost, true, int64(duration.Seconds()))
} }
func handleStreamCache(a *Bouncer, initialized bool) { func handleStreamCache(a *Bouncer) {
// TODO clean properly on exit. // TODO clean properly on exit.
time.AfterFunc(time.Duration(a.updateInterval)*time.Second, func() {
handleStreamCache(a, false)
})
var rawQuery string var rawQuery string
var path string var path string
if a.crowdsecMode == aloneMode { if a.crowdsecMode == aloneMode {
rawQuery = "" rawQuery = ""
path = crowdsecCapiDecisions path = crowdsecCapiDecisions
} else { } else {
rawQuery = fmt.Sprintf("startup=%t", initialized) rawQuery = fmt.Sprintf("startup=%t", !a.crowdsecStreamHealthy)
path = crowdsecLapiStreamRoute path = crowdsecLapiStreamRoute
} }
streamRouteURL := url.URL{ streamRouteURL := url.URL{
@@ -289,7 +293,7 @@ func handleStreamCache(a *Bouncer, initialized bool) {
var stream Stream var stream Stream
err := json.Unmarshal(body, &stream) err := json.Unmarshal(body, &stream)
if err != nil { if err != nil {
log.Printf("error while parsing body: %s", err) logger(fmt.Sprintf("error while parsing body: %s", err))
a.crowdsecStreamHealthy = false a.crowdsecStreamHealthy = false
return return
} }
@@ -315,7 +319,7 @@ func getToken(a *Bouncer) {
var login Login var login Login
err := json.Unmarshal(body, &login) err := json.Unmarshal(body, &login)
if err != nil { if err != nil {
log.Printf("error while parsing body: %s", err) logger(fmt.Sprintf("error while parsing body: %s", err))
a.crowdsecStreamHealthy = false a.crowdsecStreamHealthy = false
return return
} }
@@ -344,7 +348,7 @@ func crowdsecQuery(a *Bouncer, stringURL string, isPost bool) []byte {
} }
res, err := a.client.Do(req) res, err := a.client.Do(req)
if err != nil { if err != nil {
log.Printf("error while fetching %v: %s", stringURL, err) logger(fmt.Sprintf("error while fetching %v: %s", stringURL, err))
a.crowdsecStreamHealthy = false a.crowdsecStreamHealthy = false
return nil return nil
} }
@@ -358,19 +362,19 @@ func crowdsecQuery(a *Bouncer, stringURL string, isPost bool) []byte {
return crowdsecQuery(a, stringURL, false) return crowdsecQuery(a, stringURL, false)
} }
if res.StatusCode != http.StatusOK { if res.StatusCode != http.StatusOK {
log.Printf("error while fetching %v, status code: %d", stringURL, res.StatusCode) logger(fmt.Sprintf("error while fetching %v, status code: %d", stringURL, res.StatusCode))
a.crowdsecStreamHealthy = false a.crowdsecStreamHealthy = false
return nil return nil
} }
defer func(body io.ReadCloser) { defer func(body io.ReadCloser) {
err = body.Close() err = body.Close()
if err != nil { if err != nil {
log.Printf("failed to close body reader: %s", err) logger(fmt.Sprintf("failed to close body reader: %s", err))
} }
}(res.Body) }(res.Body)
body, err := ioutil.ReadAll(res.Body) body, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
log.Printf("error while reading body: %s", err) logger(fmt.Sprintf("error while reading body: %s", err))
a.crowdsecStreamHealthy = false a.crowdsecStreamHealthy = false
return nil return nil
} }
+29 -17
View File
@@ -7,7 +7,7 @@ services:
command: command:
# - "--log.level=DEBUG" # - "--log.level=DEBUG"
- "--accesslog" - "--accesslog"
- "--accesslog.filepath=/var/log/traefik/traefik.log" - "--accesslog.filepath=/var/log/traefik/access.log"
- "--api.insecure=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"
@@ -15,28 +15,40 @@ services:
- "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
volumes: volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro" - /var/run/docker.sock:/var/run/docker.sock:ro
- "logs:/var/log/traefik" - logs:/var/log/traefik
- ./:/plugins-local/src/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin - ./:/plugins-local/src/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
ports:
- 8000:80
- 8080:8080
depends_on:
- 'crowdsec'
whoami:
image: traefik/whoami
container_name: "simple-service"
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.routers.whoami.middlewares=crowdsec@docker"
- "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true" - "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true"
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapikey=40796d93c2958f9e58345514e67740e5" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapikey=40796d93c2958f9e58345514e67740e5"
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapilogin=3829a6c9870e4726a377d8951ebb64a1m8psGvMaq1ykJ3zX" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapilogin=3829a6c9870e4726a377d8951ebb64a1m8psGvMaq1ykJ3zX"
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapipwd=Q5pgN8bRNInHGdx6QCksdPOJVLeLQ7ipJntSeuP3r8088zXzRVs4G8liXAKfI1k6" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapipwd=Q5pgN8bRNInHGdx6QCksdPOJVLeLQ7ipJntSeuP3r8088zXzRVs4G8liXAKfI1k6"
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapiscenarios=crowdsecurity/http-backdoors-attempts,baudneo/zoneminder-bf" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseccapiscenarios=crowdsecurity/http-backdoors-attempts,baudneo/zoneminder-bf"
ports:
- 8000:80
- 8080:8080
depends_on:
- crowdsec
whoami1:
image: traefik/whoami
container_name: "simple-service1"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.routers.whoami.middlewares=crowdsec@docker"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
whoami2:
image: traefik/whoami
container_name: "simple-service2"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.http.routers.whoami.middlewares=crowdsec@docker"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
crowdsec: crowdsec:
image: crowdsecurity/crowdsec:v1.4.1 image: crowdsecurity/crowdsec:v1.4.1
@@ -49,8 +61,8 @@ services:
volumes: volumes:
- ./acquis.yaml:/etc/crowdsec/acquis.yaml:ro - ./acquis.yaml:/etc/crowdsec/acquis.yaml:ro
- logs:/var/log/traefik:ro - logs:/var/log/traefik:ro
- crowdsec-db:/var/lib/crowdsec/data/ - db:/var/lib/crowdsec/data/
- crowdsec-config:/etc/crowdsec/ - config:/etc/crowdsec/
volumes: volumes:
logs: logs:
+1 -1
View File
@@ -7,7 +7,7 @@ services:
command: command:
# - "--log.level=DEBUG" # - "--log.level=DEBUG"
- "--accesslog" - "--accesslog"
- "--accesslog.filepath=/var/log/traefik/traefik.log" - "--accesslog.filepath=/var/log/traefik/access.log"
- "--api.insecure=true" - "--api.insecure=true"
- "--providers.docker=true" - "--providers.docker=true"
- "--providers.docker.exposedbydefault=false" - "--providers.docker.exposedbydefault=false"