mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-07-21 11:38:59 +02:00
✨ Add env for RemediationStatusCode (#250)
* ✨ Add env for defaultStatusCode * 📝 doc * ✨change name of the parameter * 🔧 Add config check * fix lint
This commit is contained in:
@@ -439,6 +439,10 @@ _By careful when you upgrade to >1.4.x_
|
|||||||
- int64
|
- int64
|
||||||
- default: 60
|
- default: 60
|
||||||
- Used only in `live` mode, maximum decision duration
|
- Used only in `live` mode, maximum decision duration
|
||||||
|
- RemediationStatusCode
|
||||||
|
- int
|
||||||
|
- default: 403
|
||||||
|
- HTTP status code for banned user (not captcha)
|
||||||
- CrowdsecCapiMachineId
|
- CrowdsecCapiMachineId
|
||||||
- string
|
- string
|
||||||
- Used only in `alone` mode, login for Crowdsec CAPI
|
- Used only in `alone` mode, login for Crowdsec CAPI
|
||||||
@@ -518,6 +522,7 @@ http:
|
|||||||
updateIntervalSeconds: 60
|
updateIntervalSeconds: 60
|
||||||
updateMaxFailure: 0
|
updateMaxFailure: 0
|
||||||
defaultDecisionSeconds: 60
|
defaultDecisionSeconds: 60
|
||||||
|
remediationStatusCode: 403
|
||||||
httpTimeoutSeconds: 10
|
httpTimeoutSeconds: 10
|
||||||
crowdsecMode: live
|
crowdsecMode: live
|
||||||
crowdsecAppsecEnabled: false
|
crowdsecAppsecEnabled: false
|
||||||
@@ -527,7 +532,6 @@ http:
|
|||||||
crowdsecAppsecUnreachableBlock: true
|
crowdsecAppsecUnreachableBlock: true
|
||||||
crowdsecAppsecBodyLimit: 10485760
|
crowdsecAppsecBodyLimit: 10485760
|
||||||
crowdsecLapiKey: privateKey-foo
|
crowdsecLapiKey: privateKey-foo
|
||||||
crowdsecLapiKeyFile: /etc/traefik/cs-privateKey-foo
|
|
||||||
crowdsecLapiScheme: http
|
crowdsecLapiScheme: http
|
||||||
crowdsecLapiHost: crowdsec:8080
|
crowdsecLapiHost: crowdsec:8080
|
||||||
crowdsecLapiPath: "/"
|
crowdsecLapiPath: "/"
|
||||||
@@ -556,7 +560,6 @@ http:
|
|||||||
...
|
...
|
||||||
Q0veeNzBQXg1f/JxfeA39IDIX1kiCf71tGlT
|
Q0veeNzBQXg1f/JxfeA39IDIX1kiCf71tGlT
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
crowdsecLapiTLSCertificateAuthorityFile: /etc/traefik/crowdsec-certs/ca.pem
|
|
||||||
crowdsecLapiTLSCertificateBouncer: |-
|
crowdsecLapiTLSCertificateBouncer: |-
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIEHjCCAwagAwIBAgIUOBTs1eqkaAUcPplztUr2xRapvNAwDQYJKoZIhvcNAQEL
|
MIIEHjCCAwagAwIBAgIUOBTs1eqkaAUcPplztUr2xRapvNAwDQYJKoZIhvcNAQEL
|
||||||
@@ -564,14 +567,12 @@ http:
|
|||||||
RaXAnYYUVRblS1jmePemh388hFxbmrpG2pITx8B5FMULqHoj11o2Rl0gSV6tHIHz
|
RaXAnYYUVRblS1jmePemh388hFxbmrpG2pITx8B5FMULqHoj11o2Rl0gSV6tHIHz
|
||||||
N2U=
|
N2U=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
crowdsecLapiTLSCertificateBouncerFile: /etc/traefik/crowdsec-certs/bouncer.pem
|
|
||||||
crowdsecLapiTLSCertificateBouncerKey: |-
|
crowdsecLapiTLSCertificateBouncerKey: |-
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEogIBAAKCAQEAtYQnbJqifH+ZymePylDxGGLIuxzcAUU4/ajNj+qRAdI/Ux3d
|
MIIEogIBAAKCAQEAtYQnbJqifH+ZymePylDxGGLIuxzcAUU4/ajNj+qRAdI/Ux3d
|
||||||
...
|
...
|
||||||
ic5cDRo6/VD3CS3MYzyBcibaGaV34nr0G/pI+KEqkYChzk/PZRA=
|
ic5cDRo6/VD3CS3MYzyBcibaGaV34nr0G/pI+KEqkYChzk/PZRA=
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
crowdsecLapiTLSCertificateBouncerKeyFile: /etc/traefik/crowdsec-certs/bouncer-key.pem
|
|
||||||
captchaProvider: hcaptcha
|
captchaProvider: hcaptcha
|
||||||
captchaSiteKey: FIXME
|
captchaSiteKey: FIXME
|
||||||
captchaSecretKey: FIXME
|
captchaSecretKey: FIXME
|
||||||
@@ -582,7 +583,7 @@ http:
|
|||||||
|
|
||||||
#### Fill variable with value of file
|
#### Fill variable with value of file
|
||||||
|
|
||||||
`CrowdsecLapiTlsCertificateBouncerKey`, `CrowdsecLapiTlsCertificateBouncer`, `CrowdsecLapiTlsCertificateAuthority`, `CrowdsecCapiMachineId`, `CrowdsecCapiPassword`, `CrowdsecLapiKey`, `CaptchaSiteKey` and `CaptchaSecretKey` can be provided with the content as raw or through a file path that Traefik can read.
|
`CrowdsecLapiTlsCertificateBouncerKey`, `CrowdsecLapiTlsCertificateBouncer`, `CrowdsecLapiTlsCertificateAuthority`, `CrowdsecCapiMachineId`, `CrowdsecCapiPassword`, `CrowdsecLapiKey`, `CaptchaSiteKey`, `CaptchaSecretKey` and `RedisCachePassword` can be provided with the content as raw or through a file path that Traefik can read.
|
||||||
The file variable will be used as preference if both content and file are provided for the same variable.
|
The file variable will be used as preference if both content and file are provided for the same variable.
|
||||||
|
|
||||||
Format is:
|
Format is:
|
||||||
|
|||||||
+4
-2
@@ -77,6 +77,7 @@ type Bouncer struct {
|
|||||||
updateInterval int64
|
updateInterval int64
|
||||||
updateMaxFailure int
|
updateMaxFailure int
|
||||||
defaultDecisionTimeout int64
|
defaultDecisionTimeout int64
|
||||||
|
remediationStatusCode int
|
||||||
remediationCustomHeader string
|
remediationCustomHeader string
|
||||||
forwardedCustomHeader string
|
forwardedCustomHeader string
|
||||||
crowdsecStreamRoute string
|
crowdsecStreamRoute string
|
||||||
@@ -170,6 +171,7 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
|||||||
remediationCustomHeader: config.RemediationHeadersCustomName,
|
remediationCustomHeader: config.RemediationHeadersCustomName,
|
||||||
forwardedCustomHeader: config.ForwardedHeadersCustomName,
|
forwardedCustomHeader: config.ForwardedHeadersCustomName,
|
||||||
defaultDecisionTimeout: config.DefaultDecisionSeconds,
|
defaultDecisionTimeout: config.DefaultDecisionSeconds,
|
||||||
|
remediationStatusCode: config.RemediationStatusCode,
|
||||||
redisUnreachableBlock: config.RedisCacheUnreachableBlock,
|
redisUnreachableBlock: config.RedisCacheUnreachableBlock,
|
||||||
banTemplateString: banTemplateString,
|
banTemplateString: banTemplateString,
|
||||||
crowdsecStreamRoute: crowdsecStreamRoute,
|
crowdsecStreamRoute: crowdsecStreamRoute,
|
||||||
@@ -355,11 +357,11 @@ func handleBanServeHTTP(bouncer *Bouncer, rw http.ResponseWriter) {
|
|||||||
rw.Header().Set(bouncer.remediationCustomHeader, "ban")
|
rw.Header().Set(bouncer.remediationCustomHeader, "ban")
|
||||||
}
|
}
|
||||||
if bouncer.banTemplateString == "" {
|
if bouncer.banTemplateString == "" {
|
||||||
rw.WriteHeader(http.StatusForbidden)
|
rw.WriteHeader(bouncer.remediationStatusCode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
rw.WriteHeader(http.StatusForbidden)
|
rw.WriteHeader(bouncer.remediationStatusCode)
|
||||||
_, err := fmt.Fprint(rw, bouncer.banTemplateString)
|
_, err := fmt.Fprint(rw, bouncer.banTemplateString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bouncer.log.Error("handleBanServeHTTP could not write template to ResponseWriter")
|
bouncer.log.Error("handleBanServeHTTP could not write template to ResponseWriter")
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ type Config struct {
|
|||||||
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
||||||
UpdateMaxFailure int `json:"updateMaxFailure,omitempty"`
|
UpdateMaxFailure int `json:"updateMaxFailure,omitempty"`
|
||||||
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
||||||
|
RemediationStatusCode int `json:"remediationStatusCode,omitempty"`
|
||||||
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
||||||
RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"`
|
RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"`
|
||||||
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
||||||
@@ -119,6 +120,7 @@ func New() *Config {
|
|||||||
UpdateIntervalSeconds: 60,
|
UpdateIntervalSeconds: 60,
|
||||||
UpdateMaxFailure: 0,
|
UpdateMaxFailure: 0,
|
||||||
DefaultDecisionSeconds: 60,
|
DefaultDecisionSeconds: 60,
|
||||||
|
RemediationStatusCode: http.StatusForbidden,
|
||||||
HTTPTimeoutSeconds: 10,
|
HTTPTimeoutSeconds: 10,
|
||||||
CaptchaProvider: "",
|
CaptchaProvider: "",
|
||||||
CaptchaSiteKey: "",
|
CaptchaSiteKey: "",
|
||||||
@@ -355,6 +357,9 @@ func validateParamsRequired(config *Config) error {
|
|||||||
if config.CrowdsecAppsecBodyLimit < 0 {
|
if config.CrowdsecAppsecBodyLimit < 0 {
|
||||||
return errors.New("CrowdsecAppsecBodyLimit: cannot be less than 0")
|
return errors.New("CrowdsecAppsecBodyLimit: cannot be less than 0")
|
||||||
}
|
}
|
||||||
|
if config.RemediationStatusCode < 100 || config.RemediationStatusCode >= 600 {
|
||||||
|
return errors.New("RemediationStatusCode: cannot be less than 100 and more than 600")
|
||||||
|
}
|
||||||
|
|
||||||
if !contains([]string{NoneMode, LiveMode, StreamMode, AloneMode, AppsecMode}, config.CrowdsecMode) {
|
if !contains([]string{NoneMode, LiveMode, StreamMode, AloneMode, AppsecMode}, config.CrowdsecMode) {
|
||||||
return errors.New("CrowdsecMode: must be one of 'none', 'live', 'stream', 'alone' or 'appsec'")
|
return errors.New("CrowdsecMode: must be one of 'none', 'live', 'stream', 'alone' or 'appsec'")
|
||||||
|
|||||||
Reference in New Issue
Block a user