mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-07-21 11:38:59 +02:00
✨ Add grace period to reach LAPI without blocking further queries (#153)
* ✨ Add grace period to reach LAPI without blocking further queries * 🐛 Fix config validation for maxFailedStreamUpdate * 🚨 Fix some lint issue * 🚨 Bypass lint complexity on ServeHTTP * 🍱 fix and improve * 🚨 Fix lint * 🚨 Fix lint * 🐛 Fix logic for update max failure * 📝 Update doc and docker compose local reset * 🍱 fix log nightmare * 🍱 fix --------- Co-authored-by: max.lerebourg <max.lerebourg@monisnap.com>
This commit is contained in:
co-authored by
max.lerebourg
parent
b6a0404efd
commit
ee97250acf
@@ -396,6 +396,10 @@ Only one instance of the plugin is *possible*.
|
|||||||
- int64
|
- int64
|
||||||
- default: 60
|
- default: 60
|
||||||
- Used only in `stream` mode, the interval between requests to fetch blacklisted IPs from LAPI
|
- Used only in `stream` mode, the interval between requests to fetch blacklisted IPs from LAPI
|
||||||
|
- UpdateMaxFailure
|
||||||
|
- int64
|
||||||
|
- default: 0
|
||||||
|
- Used only in `stream` and `alone` mode, the maximum number of time we can not reach Crowdsec before blocking traffic (set -1 to never block)
|
||||||
- DefaultDecisionSeconds
|
- DefaultDecisionSeconds
|
||||||
- int64
|
- int64
|
||||||
- default: 60
|
- default: 60
|
||||||
@@ -475,6 +479,7 @@ http:
|
|||||||
enabled: false
|
enabled: false
|
||||||
logLevel: DEBUG
|
logLevel: DEBUG
|
||||||
updateIntervalSeconds: 60
|
updateIntervalSeconds: 60
|
||||||
|
updateMaxFailure: 0
|
||||||
defaultDecisionSeconds: 60
|
defaultDecisionSeconds: 60
|
||||||
httpTimeoutSeconds: 10
|
httpTimeoutSeconds: 10
|
||||||
crowdsecMode: live
|
crowdsecMode: live
|
||||||
|
|||||||
+10
-4
@@ -43,6 +43,7 @@ const (
|
|||||||
var (
|
var (
|
||||||
isStartup = true
|
isStartup = true
|
||||||
isCrowdsecStreamHealthy = true
|
isCrowdsecStreamHealthy = true
|
||||||
|
updateFailure = 0
|
||||||
ticker chan bool
|
ticker chan bool
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ type Bouncer struct {
|
|||||||
crowdsecPassword string
|
crowdsecPassword string
|
||||||
crowdsecScenarios []string
|
crowdsecScenarios []string
|
||||||
updateInterval int64
|
updateInterval int64
|
||||||
|
updateMaxFailure int
|
||||||
defaultDecisionTimeout int64
|
defaultDecisionTimeout int64
|
||||||
customHeader string
|
customHeader string
|
||||||
crowdsecStreamRoute string
|
crowdsecStreamRoute string
|
||||||
@@ -150,6 +152,7 @@ func New(ctx context.Context, next http.Handler, config *configuration.Config, n
|
|||||||
crowdsecPassword: config.CrowdsecCapiPassword,
|
crowdsecPassword: config.CrowdsecCapiPassword,
|
||||||
crowdsecScenarios: config.CrowdsecCapiScenarios,
|
crowdsecScenarios: config.CrowdsecCapiScenarios,
|
||||||
updateInterval: config.UpdateIntervalSeconds,
|
updateInterval: config.UpdateIntervalSeconds,
|
||||||
|
updateMaxFailure: config.UpdateMaxFailure,
|
||||||
customHeader: config.ForwardedHeadersCustomName,
|
customHeader: config.ForwardedHeadersCustomName,
|
||||||
defaultDecisionTimeout: config.DefaultDecisionSeconds,
|
defaultDecisionTimeout: config.DefaultDecisionSeconds,
|
||||||
banTemplateString: banTemplateString,
|
banTemplateString: banTemplateString,
|
||||||
@@ -282,7 +285,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
if isCrowdsecStreamHealthy {
|
if isCrowdsecStreamHealthy {
|
||||||
handleNextServeHTTP(bouncer, remoteIP, rw, req)
|
handleNextServeHTTP(bouncer, remoteIP, rw, req)
|
||||||
} else {
|
} else {
|
||||||
bouncer.log.Debug(fmt.Sprintf("ServeHTTP isCrowdsecStreamHealthy:false ip:%s", remoteIP))
|
bouncer.log.Debug(fmt.Sprintf("ServeHTTP isCrowdsecStreamHealthy:false ip:%s updateFailure:%d", remoteIP, updateFailure))
|
||||||
handleBanServeHTTP(bouncer, rw)
|
handleBanServeHTTP(bouncer, rw)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -358,10 +361,15 @@ func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWrit
|
|||||||
|
|
||||||
func handleStreamTicker(bouncer *Bouncer) {
|
func handleStreamTicker(bouncer *Bouncer) {
|
||||||
if err := handleStreamCache(bouncer); err != nil {
|
if err := handleStreamCache(bouncer); err != nil {
|
||||||
|
bouncer.log.Debug(fmt.Sprintf("handleStreamTicker updateFailure:%d isCrowdsecStreamHealthy:%t %s", updateFailure, isCrowdsecStreamHealthy, err.Error()))
|
||||||
|
if bouncer.updateMaxFailure != -1 && updateFailure >= bouncer.updateMaxFailure && isCrowdsecStreamHealthy {
|
||||||
isCrowdsecStreamHealthy = false
|
isCrowdsecStreamHealthy = false
|
||||||
bouncer.log.Error(err.Error())
|
bouncer.log.Error(fmt.Sprintf("handleStreamTicker:error updateFailure:%d %s", updateFailure, err.Error()))
|
||||||
|
}
|
||||||
|
updateFailure++
|
||||||
} else {
|
} else {
|
||||||
isCrowdsecStreamHealthy = true
|
isCrowdsecStreamHealthy = true
|
||||||
|
updateFailure = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +465,6 @@ func getToken(bouncer *Bouncer) error {
|
|||||||
var login Login
|
var login Login
|
||||||
err = json.Unmarshal(body, &login)
|
err = json.Unmarshal(body, &login)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
isCrowdsecStreamHealthy = false
|
|
||||||
return fmt.Errorf("getToken:parsingBody %w", err)
|
return fmt.Errorf("getToken:parsingBody %w", err)
|
||||||
}
|
}
|
||||||
if login.Code == 200 && len(login.Token) > 0 {
|
if login.Code == 200 && len(login.Token) > 0 {
|
||||||
@@ -516,7 +523,6 @@ func handleStreamCache(bouncer *Bouncer) error {
|
|||||||
bouncer.cacheClient.Delete(decision.Value)
|
bouncer.cacheClient.Delete(decision.Value)
|
||||||
}
|
}
|
||||||
bouncer.log.Debug("handleStreamCache:updated")
|
bouncer.log.Debug("handleStreamCache:updated")
|
||||||
isCrowdsecStreamHealthy = true
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ type Config struct {
|
|||||||
CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"`
|
CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"`
|
||||||
CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"`
|
CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"`
|
||||||
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
||||||
|
UpdateMaxFailure int `json:"updateMaxFailure,omitempty"`
|
||||||
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
||||||
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
||||||
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
||||||
@@ -100,6 +101,7 @@ func New() *Config {
|
|||||||
CrowdsecLapiKey: "",
|
CrowdsecLapiKey: "",
|
||||||
CrowdsecLapiTLSInsecureVerify: false,
|
CrowdsecLapiTLSInsecureVerify: false,
|
||||||
UpdateIntervalSeconds: 60,
|
UpdateIntervalSeconds: 60,
|
||||||
|
UpdateMaxFailure: 0,
|
||||||
DefaultDecisionSeconds: 60,
|
DefaultDecisionSeconds: 60,
|
||||||
HTTPTimeoutSeconds: 10,
|
HTTPTimeoutSeconds: 10,
|
||||||
CaptchaProvider: "",
|
CaptchaProvider: "",
|
||||||
@@ -318,6 +320,10 @@ func validateParamsRequired(config *Config) error {
|
|||||||
return fmt.Errorf("%v: cannot be less than 1", key)
|
return fmt.Errorf("%v: cannot be less than 1", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.UpdateMaxFailure < -1 {
|
||||||
|
return fmt.Errorf("UpdateMaxFailure: cannot be less than -1")
|
||||||
|
}
|
||||||
|
|
||||||
if !contains([]string{NoneMode, LiveMode, StreamMode, AloneMode, AppsecMode}, config.CrowdsecMode) {
|
if !contains([]string{NoneMode, LiveMode, StreamMode, AloneMode, AppsecMode}, config.CrowdsecMode) {
|
||||||
return fmt.Errorf("CrowdsecMode: must be one of 'none', 'live', 'stream', 'alone' or 'appsec'")
|
return fmt.Errorf("CrowdsecMode: must be one of 'none', 'live', 'stream', 'alone' or 'appsec'")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user