mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-07-21 11:38:59 +02:00
✨ Separate TLS conf for LAPI and Appsec (#293)
* ✨ Separate TLS conf for LAPI and Appsec * 🍱 fix lint * 🍱 fix test * 🍱 fix lint * 🍱 fix lint * 🍱 fix lint * 🍱 fix lint ? * 🍱 fix lint * 🍱 Add default for traceCustomHeaders
This commit is contained in:
@@ -554,6 +554,7 @@ http:
|
|||||||
httpTimeoutSeconds: 10
|
httpTimeoutSeconds: 10
|
||||||
crowdsecMode: live
|
crowdsecMode: live
|
||||||
crowdsecAppsecEnabled: false
|
crowdsecAppsecEnabled: false
|
||||||
|
crowdsecAppsecScheme: ""
|
||||||
crowdsecAppsecHost: crowdsec:7422
|
crowdsecAppsecHost: crowdsec:7422
|
||||||
crowdsecAppsecPath: "/"
|
crowdsecAppsecPath: "/"
|
||||||
crowdsecAppsecFailureBlock: true
|
crowdsecAppsecFailureBlock: true
|
||||||
|
|||||||
+33
-9
@@ -85,8 +85,10 @@ type Bouncer struct {
|
|||||||
|
|
||||||
enabled bool
|
enabled bool
|
||||||
appsecEnabled bool
|
appsecEnabled bool
|
||||||
|
appsecScheme string
|
||||||
appsecHost string
|
appsecHost string
|
||||||
appsecPath string
|
appsecPath string
|
||||||
|
appsecKey string
|
||||||
appsecFailureBlock bool
|
appsecFailureBlock bool
|
||||||
appsecUnreachableBlock bool
|
appsecUnreachableBlock bool
|
||||||
appsecBodyLimit int64
|
appsecBodyLimit int64
|
||||||
@@ -112,6 +114,7 @@ type Bouncer struct {
|
|||||||
clientPoolStrategy *ip.PoolStrategy
|
clientPoolStrategy *ip.PoolStrategy
|
||||||
serverPoolStrategy *ip.PoolStrategy
|
serverPoolStrategy *ip.PoolStrategy
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
|
httpAppsecClient *http.Client
|
||||||
cacheClient *cache.Client
|
cacheClient *cache.Client
|
||||||
captchaClient *captcha.Client
|
captchaClient *captcha.Client
|
||||||
log *logger.Log
|
log *logger.Log
|
||||||
@@ -131,6 +134,17 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
|||||||
|
|
||||||
serverChecker, _ := ip.NewChecker(log, config.ForwardedHeadersTrustedIPs)
|
serverChecker, _ := ip.NewChecker(log, config.ForwardedHeadersTrustedIPs)
|
||||||
clientChecker, _ := ip.NewChecker(log, config.ClientTrustedIPs)
|
clientChecker, _ := ip.NewChecker(log, config.ClientTrustedIPs)
|
||||||
|
tlsAppsecConfig, err := configuration.GetTLSConfigCrowdsec(config, log, true)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("New:getTLSConfigCrowdsec fail to get tlsAppsecConfig " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
apiAppsecKey, errAppsecKey := configuration.GetVariable(config, "CrowdsecAppsecKey")
|
||||||
|
if errAppsecKey != nil && len(tlsAppsecConfig.Certificates) == 0 {
|
||||||
|
log.Error("New:crowdsecLapiKey fail to get CrowdsecAppsecKey and no client certificate setup " + errAppsecKey.Error())
|
||||||
|
return nil, errAppsecKey
|
||||||
|
}
|
||||||
|
config.CrowdsecAppsecKey = apiAppsecKey
|
||||||
|
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
crowdsecStreamRoute := ""
|
crowdsecStreamRoute := ""
|
||||||
@@ -141,22 +155,22 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
|||||||
config.CrowdsecLapiScheme = configuration.HTTPS
|
config.CrowdsecLapiScheme = configuration.HTTPS
|
||||||
config.CrowdsecLapiHost = crowdsecCapiHost
|
config.CrowdsecLapiHost = crowdsecCapiHost
|
||||||
config.CrowdsecLapiPath = "/"
|
config.CrowdsecLapiPath = "/"
|
||||||
config.CrowdsecAppsecEnabled = false
|
config.CrowdsecAppsecEnabled = config.CrowdsecAppsecEnabled && config.CrowdsecAppsecScheme != ""
|
||||||
config.UpdateIntervalSeconds = 7200 // 2 hours
|
config.UpdateIntervalSeconds = 7200 // 2 hours
|
||||||
crowdsecStreamRoute = crowdsecCapiStreamRoute
|
crowdsecStreamRoute = crowdsecCapiStreamRoute
|
||||||
crowdsecHeader = crowdsecCapiHeader
|
crowdsecHeader = crowdsecCapiHeader
|
||||||
} else {
|
} else {
|
||||||
crowdsecStreamRoute = crowdsecLapiStreamRoute
|
crowdsecStreamRoute = crowdsecLapiStreamRoute
|
||||||
crowdsecHeader = crowdsecLapiHeader
|
crowdsecHeader = crowdsecLapiHeader
|
||||||
tlsConfig, err = configuration.GetTLSConfigCrowdsec(config, log)
|
tlsConfig, err = configuration.GetTLSConfigCrowdsec(config, log, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("New:getTLSConfigCrowdsec fail to get tlsConfig " + err.Error())
|
log.Error("New:getTLSConfigCrowdsec fail to get tlsConfig " + err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
apiKey, errAPIKey := configuration.GetVariable(config, "CrowdsecLapiKey")
|
apiKey, errKey := configuration.GetVariable(config, "CrowdsecLapiKey")
|
||||||
if errAPIKey != nil && len(tlsConfig.Certificates) == 0 {
|
if errKey != nil && len(tlsConfig.Certificates) == 0 {
|
||||||
log.Error("New:crowdsecLapiKey fail to get CrowdsecLapiKey and no client certificate setup " + errAPIKey.Error())
|
log.Error("New:crowdsecLapiKey fail to get CrowdsecLapiKey and no client certificate setup " + errKey.Error())
|
||||||
return nil, errAPIKey
|
return nil, errKey
|
||||||
}
|
}
|
||||||
config.CrowdsecLapiKey = apiKey
|
config.CrowdsecLapiKey = apiKey
|
||||||
}
|
}
|
||||||
@@ -174,8 +188,10 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
|||||||
enabled: config.Enabled,
|
enabled: config.Enabled,
|
||||||
crowdsecMode: config.CrowdsecMode,
|
crowdsecMode: config.CrowdsecMode,
|
||||||
appsecEnabled: config.CrowdsecAppsecEnabled,
|
appsecEnabled: config.CrowdsecAppsecEnabled,
|
||||||
|
appsecScheme: config.CrowdsecAppsecScheme,
|
||||||
appsecHost: config.CrowdsecAppsecHost,
|
appsecHost: config.CrowdsecAppsecHost,
|
||||||
appsecPath: config.CrowdsecAppsecPath,
|
appsecPath: config.CrowdsecAppsecPath,
|
||||||
|
appsecKey: config.CrowdsecAppsecKey,
|
||||||
appsecFailureBlock: config.CrowdsecAppsecFailureBlock,
|
appsecFailureBlock: config.CrowdsecAppsecFailureBlock,
|
||||||
appsecUnreachableBlock: config.CrowdsecAppsecUnreachableBlock,
|
appsecUnreachableBlock: config.CrowdsecAppsecUnreachableBlock,
|
||||||
appsecBodyLimit: config.CrowdsecAppsecBodyLimit,
|
appsecBodyLimit: config.CrowdsecAppsecBodyLimit,
|
||||||
@@ -212,6 +228,14 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
|||||||
},
|
},
|
||||||
Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second,
|
Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second,
|
||||||
},
|
},
|
||||||
|
httpAppsecClient: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
MaxIdleConns: 10,
|
||||||
|
IdleConnTimeout: 30 * time.Second,
|
||||||
|
TLSClientConfig: tlsAppsecConfig,
|
||||||
|
},
|
||||||
|
Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second,
|
||||||
|
},
|
||||||
cacheClient: &cache.Client{},
|
cacheClient: &cache.Client{},
|
||||||
captchaClient: &captcha.Client{},
|
captchaClient: &captcha.Client{},
|
||||||
}
|
}
|
||||||
@@ -672,7 +696,7 @@ func crowdsecQuery(bouncer *Bouncer, stringURL string, data []byte) ([]byte, err
|
|||||||
|
|
||||||
func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error {
|
func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error {
|
||||||
routeURL := url.URL{
|
routeURL := url.URL{
|
||||||
Scheme: bouncer.crowdsecScheme,
|
Scheme: bouncer.appsecScheme,
|
||||||
Host: bouncer.appsecHost,
|
Host: bouncer.appsecHost,
|
||||||
Path: bouncer.appsecPath,
|
Path: bouncer.appsecPath,
|
||||||
}
|
}
|
||||||
@@ -697,14 +721,14 @@ func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error {
|
|||||||
req.Header.Add(key, value)
|
req.Header.Add(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req.Header.Set(crowdsecAppsecHeader, bouncer.crowdsecKey)
|
req.Header.Set(crowdsecAppsecHeader, bouncer.appsecKey)
|
||||||
req.Header.Set(crowdsecAppsecIPHeader, ip)
|
req.Header.Set(crowdsecAppsecIPHeader, ip)
|
||||||
req.Header.Set(crowdsecAppsecVerbHeader, httpReq.Method)
|
req.Header.Set(crowdsecAppsecVerbHeader, httpReq.Method)
|
||||||
req.Header.Set(crowdsecAppsecHostHeader, httpReq.Host)
|
req.Header.Set(crowdsecAppsecHostHeader, httpReq.Host)
|
||||||
req.Header.Set(crowdsecAppsecURIHeader, httpReq.URL.String())
|
req.Header.Set(crowdsecAppsecURIHeader, httpReq.URL.String())
|
||||||
req.Header.Set(crowdsecAppsecUserAgent, httpReq.Header.Get("User-Agent"))
|
req.Header.Set(crowdsecAppsecUserAgent, httpReq.Header.Get("User-Agent"))
|
||||||
|
|
||||||
res, err := bouncer.httpClient.Do(req)
|
res, err := bouncer.httpAppsecClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bouncer.log.Error("appsecQuery:unreachable")
|
bouncer.log.Error("appsecQuery:unreachable")
|
||||||
if bouncer.appsecUnreachableBlock {
|
if bouncer.appsecUnreachableBlock {
|
||||||
|
|||||||
@@ -89,4 +89,8 @@ make run_tlsauth
|
|||||||
```
|
```
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
> Traefik need to be restart if certificates are regenerated after his launch
|
> Traefik need to be restarted if certificates are regenerated after his launch
|
||||||
|
|
||||||
|
## Separate LAPI and Appsec HTTP/S config
|
||||||
|
To separate TLS config for LAPI and Appsec, you can use all the TLS LAPI variable beginning with `CrowdsecLapi...` into `CrowdsecAppsec...`.
|
||||||
|
Don't forget to set `CrowdsecAppsecScheme: HTTP` or `HTTPS` to trigger the separate setup.
|
||||||
|
|||||||
+135
-111
@@ -42,62 +42,71 @@ const (
|
|||||||
|
|
||||||
// Config the plugin configuration.
|
// Config the plugin configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
LogLevel string `json:"logLevel,omitempty"`
|
LogLevel string `json:"logLevel,omitempty"`
|
||||||
LogFilePath string `json:"logFilePath,omitempty"`
|
LogFilePath string `json:"logFilePath,omitempty"`
|
||||||
CrowdsecMode string `json:"crowdsecMode,omitempty"`
|
CrowdsecMode string `json:"crowdsecMode,omitempty"`
|
||||||
CrowdsecAppsecEnabled bool `json:"crowdsecAppsecEnabled,omitempty"`
|
CrowdsecAppsecEnabled bool `json:"crowdsecAppsecEnabled,omitempty"`
|
||||||
CrowdsecAppsecHost string `json:"crowdsecAppsecHost,omitempty"`
|
CrowdsecAppsecScheme string `json:"crowdsecAppsecScheme,omitempty"`
|
||||||
CrowdsecAppsecPath string `json:"crowdsecAppsecPath,omitempty"`
|
CrowdsecAppsecHost string `json:"crowdsecAppsecHost,omitempty"`
|
||||||
CrowdsecAppsecFailureBlock bool `json:"crowdsecAppsecFailureBlock,omitempty"`
|
CrowdsecAppsecPath string `json:"crowdsecAppsecPath,omitempty"`
|
||||||
CrowdsecAppsecUnreachableBlock bool `json:"crowdsecAppsecUnreachableBlock,omitempty"`
|
CrowdsecAppsecKey string `json:"crowdsecAppsecKey,omitempty"`
|
||||||
CrowdsecAppsecBodyLimit int64 `json:"crowdsecAppsecBodyLimit,omitempty"`
|
CrowdsecAppsecKeyFile string `json:"crowdsecAppsecKeyFile,omitempty"`
|
||||||
CrowdsecLapiScheme string `json:"crowdsecLapiScheme,omitempty"`
|
CrowdsecAppsecTLSInsecureVerify bool `json:"crowdsecAppsecTlsInsecureVerify,omitempty"`
|
||||||
CrowdsecLapiHost string `json:"crowdsecLapiHost,omitempty"`
|
CrowdsecAppsecTLSCertificateAuthority string `json:"crowdsecAppsecTlsCertificateAuthority,omitempty"`
|
||||||
CrowdsecLapiPath string `json:"crowdsecLapiPath,omitempty"`
|
CrowdsecAppsecTLSCertificateAuthorityFile string `json:"crowdsecAppsecTlsCertificateAuthorityFile,omitempty"`
|
||||||
CrowdsecLapiKey string `json:"crowdsecLapiKey,omitempty"`
|
CrowdsecAppsecTLSCertificateBouncer string `json:"crowdsecAppsecTlsCertificateBouncer,omitempty"`
|
||||||
CrowdsecLapiKeyFile string `json:"crowdsecLapiKeyFile,omitempty"`
|
CrowdsecAppsecTLSCertificateBouncerFile string `json:"crowdsecAppsecTlsCertificateBouncerFile,omitempty"`
|
||||||
CrowdsecLapiTLSInsecureVerify bool `json:"crowdsecLapiTlsInsecureVerify,omitempty"`
|
CrowdsecAppsecTLSCertificateBouncerKey string `json:"crowdsecAppsecTlsCertificateBouncerKey,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateAuthority string `json:"crowdsecLapiTlsCertificateAuthority,omitempty"`
|
CrowdsecAppsecFailureBlock bool `json:"crowdsecAppsecFailureBlock,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateAuthorityFile string `json:"crowdsecLapiTlsCertificateAuthorityFile,omitempty"`
|
CrowdsecAppsecUnreachableBlock bool `json:"crowdsecAppsecUnreachableBlock,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateBouncer string `json:"crowdsecLapiTlsCertificateBouncer,omitempty"`
|
CrowdsecAppsecBodyLimit int64 `json:"crowdsecAppsecBodyLimit,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateBouncerFile string `json:"crowdsecLapiTlsCertificateBouncerFile,omitempty"`
|
CrowdsecLapiScheme string `json:"crowdsecLapiScheme,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateBouncerKey string `json:"crowdsecLapiTlsCertificateBouncerKey,omitempty"`
|
CrowdsecLapiHost string `json:"crowdsecLapiHost,omitempty"`
|
||||||
CrowdsecLapiTLSCertificateBouncerKeyFile string `json:"crowdsecLapiTlsCertificateBouncerKeyFile,omitempty"`
|
CrowdsecLapiPath string `json:"crowdsecLapiPath,omitempty"`
|
||||||
CrowdsecCapiMachineID string `json:"crowdsecCapiMachineId,omitempty"`
|
CrowdsecLapiKey string `json:"crowdsecLapiKey,omitempty"`
|
||||||
CrowdsecCapiMachineIDFile string `json:"crowdsecCapiMachineIdFile,omitempty"`
|
CrowdsecLapiKeyFile string `json:"crowdsecLapiKeyFile,omitempty"`
|
||||||
CrowdsecCapiPassword string `json:"crowdsecCapiPassword,omitempty"`
|
CrowdsecLapiTLSInsecureVerify bool `json:"crowdsecLapiTlsInsecureVerify,omitempty"`
|
||||||
CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"`
|
CrowdsecLapiTLSCertificateAuthority string `json:"crowdsecLapiTlsCertificateAuthority,omitempty"`
|
||||||
CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"`
|
CrowdsecLapiTLSCertificateAuthorityFile string `json:"crowdsecLapiTlsCertificateAuthorityFile,omitempty"`
|
||||||
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
CrowdsecLapiTLSCertificateBouncer string `json:"crowdsecLapiTlsCertificateBouncer,omitempty"`
|
||||||
MetricsUpdateIntervalSeconds int64 `json:"metricsUpdateIntervalSeconds,omitempty"`
|
CrowdsecLapiTLSCertificateBouncerFile string `json:"crowdsecLapiTlsCertificateBouncerFile,omitempty"`
|
||||||
UpdateMaxFailure int64 `json:"updateMaxFailure,omitempty"`
|
CrowdsecLapiTLSCertificateBouncerKey string `json:"crowdsecLapiTlsCertificateBouncerKey,omitempty"`
|
||||||
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
CrowdsecLapiTLSCertificateBouncerKeyFile string `json:"crowdsecLapiTlsCertificateBouncerKeyFile,omitempty"`
|
||||||
RemediationStatusCode int `json:"remediationStatusCode,omitempty"`
|
CrowdsecCapiMachineID string `json:"crowdsecCapiMachineId,omitempty"`
|
||||||
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
CrowdsecCapiMachineIDFile string `json:"crowdsecCapiMachineIdFile,omitempty"`
|
||||||
RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"`
|
CrowdsecCapiPassword string `json:"crowdsecCapiPassword,omitempty"`
|
||||||
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"`
|
||||||
ForwardedHeadersTrustedIPs []string `json:"forwardedHeadersTrustedIps,omitempty"`
|
CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"`
|
||||||
ClientTrustedIPs []string `json:"clientTrustedIps,omitempty"`
|
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"`
|
||||||
RedisCacheEnabled bool `json:"redisCacheEnabled,omitempty"`
|
MetricsUpdateIntervalSeconds int64 `json:"metricsUpdateIntervalSeconds,omitempty"`
|
||||||
RedisCacheHost string `json:"redisCacheHost,omitempty"`
|
UpdateMaxFailure int64 `json:"updateMaxFailure,omitempty"`
|
||||||
RedisCachePassword string `json:"redisCachePassword,omitempty"`
|
DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"`
|
||||||
RedisCachePasswordFile string `json:"redisCachePasswordFile,omitempty"`
|
RemediationStatusCode int `json:"remediationStatusCode,omitempty"`
|
||||||
RedisCacheDatabase string `json:"redisCacheDatabase,omitempty"`
|
HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"`
|
||||||
RedisCacheUnreachableBlock bool `json:"redisCacheUnreachableBlock,omitempty"`
|
TraceHeadersCustomName string `json:"traceHeadersCustomName,omitempty"`
|
||||||
BanHTMLFilePath string `json:"banHtmlFilePath,omitempty"`
|
RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"`
|
||||||
TraceHeadersCustomName string `json:"traceHeadersCustomName,omitempty"`
|
ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"`
|
||||||
CaptchaHTMLFilePath string `json:"captchaHtmlFilePath,omitempty"`
|
ForwardedHeadersTrustedIPs []string `json:"forwardedHeadersTrustedIps,omitempty"`
|
||||||
CaptchaProvider string `json:"captchaProvider,omitempty"`
|
ClientTrustedIPs []string `json:"clientTrustedIps,omitempty"`
|
||||||
CaptchaCustomJsURL string `json:"captchaCustomJsUrl,omitempty"`
|
RedisCacheEnabled bool `json:"redisCacheEnabled,omitempty"`
|
||||||
CaptchaCustomValidateURL string `json:"captchaCustomValidateUrl,omitempty"`
|
RedisCacheHost string `json:"redisCacheHost,omitempty"`
|
||||||
CaptchaCustomKey string `json:"captchaCustomKey,omitempty"`
|
RedisCachePassword string `json:"redisCachePassword,omitempty"`
|
||||||
CaptchaCustomResponse string `json:"captchaCustomResponse,omitempty"`
|
RedisCachePasswordFile string `json:"redisCachePasswordFile,omitempty"`
|
||||||
CaptchaSiteKey string `json:"captchaSiteKey,omitempty"`
|
RedisCacheDatabase string `json:"redisCacheDatabase,omitempty"`
|
||||||
CaptchaSiteKeyFile string `json:"captchaSiteKeyFile,omitempty"`
|
RedisCacheUnreachableBlock bool `json:"redisCacheUnreachableBlock,omitempty"`
|
||||||
CaptchaSecretKey string `json:"captchaSecretKey,omitempty"`
|
BanHTMLFilePath string `json:"banHtmlFilePath,omitempty"`
|
||||||
CaptchaSecretKeyFile string `json:"captchaSecretKeyFile,omitempty"`
|
CaptchaHTMLFilePath string `json:"captchaHtmlFilePath,omitempty"`
|
||||||
CaptchaGracePeriodSeconds int64 `json:"captchaGracePeriodSeconds,omitempty"`
|
CaptchaProvider string `json:"captchaProvider,omitempty"`
|
||||||
|
CaptchaCustomJsURL string `json:"captchaCustomJsUrl,omitempty"`
|
||||||
|
CaptchaCustomValidateURL string `json:"captchaCustomValidateUrl,omitempty"`
|
||||||
|
CaptchaCustomKey string `json:"captchaCustomKey,omitempty"`
|
||||||
|
CaptchaCustomResponse string `json:"captchaCustomResponse,omitempty"`
|
||||||
|
CaptchaSiteKey string `json:"captchaSiteKey,omitempty"`
|
||||||
|
CaptchaSiteKeyFile string `json:"captchaSiteKeyFile,omitempty"`
|
||||||
|
CaptchaSecretKey string `json:"captchaSecretKey,omitempty"`
|
||||||
|
CaptchaSecretKeyFile string `json:"captchaSecretKeyFile,omitempty"`
|
||||||
|
CaptchaGracePeriodSeconds int64 `json:"captchaGracePeriodSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(source []string, target string) bool {
|
func contains(source []string, target string) bool {
|
||||||
@@ -112,46 +121,50 @@ func contains(source []string, target string) bool {
|
|||||||
// New creates the default plugin configuration.
|
// New creates the default plugin configuration.
|
||||||
func New() *Config {
|
func New() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
LogLevel: LogINFO,
|
LogLevel: LogINFO,
|
||||||
LogFilePath: "",
|
LogFilePath: "",
|
||||||
CrowdsecMode: LiveMode,
|
CrowdsecMode: LiveMode,
|
||||||
CrowdsecAppsecEnabled: false,
|
CrowdsecAppsecEnabled: false,
|
||||||
CrowdsecAppsecHost: "crowdsec:7422",
|
CrowdsecAppsecFailureBlock: true,
|
||||||
CrowdsecAppsecPath: "/",
|
CrowdsecAppsecUnreachableBlock: true,
|
||||||
CrowdsecAppsecFailureBlock: true,
|
CrowdsecAppsecBodyLimit: 10485760,
|
||||||
CrowdsecAppsecUnreachableBlock: true,
|
CrowdsecAppsecScheme: "",
|
||||||
CrowdsecAppsecBodyLimit: 10485760,
|
CrowdsecAppsecHost: "crowdsec:7422",
|
||||||
CrowdsecLapiScheme: HTTP,
|
CrowdsecAppsecPath: "/",
|
||||||
CrowdsecLapiHost: "crowdsec:8080",
|
CrowdsecAppsecKey: "",
|
||||||
CrowdsecLapiPath: "/",
|
CrowdsecAppsecTLSInsecureVerify: false,
|
||||||
CrowdsecLapiKey: "",
|
CrowdsecLapiScheme: HTTP,
|
||||||
CrowdsecLapiTLSInsecureVerify: false,
|
CrowdsecLapiHost: "crowdsec:8080",
|
||||||
UpdateIntervalSeconds: 60,
|
CrowdsecLapiPath: "/",
|
||||||
MetricsUpdateIntervalSeconds: 600,
|
CrowdsecLapiKey: "",
|
||||||
UpdateMaxFailure: 0,
|
CrowdsecLapiTLSInsecureVerify: false,
|
||||||
DefaultDecisionSeconds: 60,
|
UpdateIntervalSeconds: 60,
|
||||||
RemediationStatusCode: http.StatusForbidden,
|
MetricsUpdateIntervalSeconds: 600,
|
||||||
HTTPTimeoutSeconds: 10,
|
UpdateMaxFailure: 0,
|
||||||
CaptchaProvider: "",
|
DefaultDecisionSeconds: 60,
|
||||||
CaptchaCustomJsURL: "",
|
RemediationStatusCode: http.StatusForbidden,
|
||||||
CaptchaCustomValidateURL: "",
|
HTTPTimeoutSeconds: 10,
|
||||||
CaptchaCustomKey: "",
|
CaptchaProvider: "",
|
||||||
CaptchaCustomResponse: "",
|
CaptchaCustomJsURL: "",
|
||||||
CaptchaSiteKey: "",
|
CaptchaCustomValidateURL: "",
|
||||||
CaptchaSecretKey: "",
|
CaptchaCustomKey: "",
|
||||||
CaptchaGracePeriodSeconds: 1800,
|
CaptchaCustomResponse: "",
|
||||||
CaptchaHTMLFilePath: "/captcha.html",
|
CaptchaSiteKey: "",
|
||||||
BanHTMLFilePath: "",
|
CaptchaSecretKey: "",
|
||||||
RemediationHeadersCustomName: "",
|
CaptchaGracePeriodSeconds: 1800,
|
||||||
ForwardedHeadersCustomName: "X-Forwarded-For",
|
CaptchaHTMLFilePath: "/captcha.html",
|
||||||
ForwardedHeadersTrustedIPs: []string{},
|
BanHTMLFilePath: "",
|
||||||
ClientTrustedIPs: []string{},
|
TraceHeadersCustomName: "",
|
||||||
RedisCacheEnabled: false,
|
RemediationHeadersCustomName: "",
|
||||||
RedisCacheHost: "redis:6379",
|
ForwardedHeadersCustomName: "X-Forwarded-For",
|
||||||
RedisCachePassword: "",
|
ForwardedHeadersTrustedIPs: []string{},
|
||||||
RedisCacheDatabase: "",
|
ClientTrustedIPs: []string{},
|
||||||
RedisCacheUnreachableBlock: true,
|
RedisCacheEnabled: false,
|
||||||
|
RedisCacheHost: "redis:6379",
|
||||||
|
RedisCachePassword: "",
|
||||||
|
RedisCacheDatabase: "",
|
||||||
|
RedisCacheUnreachableBlock: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,26 +426,27 @@ func validateParamsRequired(config *Config) error {
|
|||||||
if !contains([]string{HTTP, HTTPS}, config.CrowdsecLapiScheme) {
|
if !contains([]string{HTTP, HTTPS}, config.CrowdsecLapiScheme) {
|
||||||
return errors.New("CrowdsecLapiScheme: must be one of 'http' or 'https'")
|
return errors.New("CrowdsecLapiScheme: must be one of 'http' or 'https'")
|
||||||
}
|
}
|
||||||
|
if !contains([]string{HTTP, HTTPS, ""}, config.CrowdsecAppsecScheme) {
|
||||||
|
return errors.New("CrowdsecAppsecScheme: must be one of 'http' or 'https'")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTLSConfigCrowdsec get TLS config from Config.
|
func getTLSConfig(config *Config, log *logger.Log, prefix, scheme string, insecureVerify bool) (*tls.Config, error) {
|
||||||
//
|
|
||||||
//nolint:nestif
|
|
||||||
func GetTLSConfigCrowdsec(config *Config, log *logger.Log) (*tls.Config, error) {
|
|
||||||
tlsConfig := new(tls.Config)
|
tlsConfig := new(tls.Config)
|
||||||
tlsConfig.RootCAs = x509.NewCertPool()
|
tlsConfig.RootCAs = x509.NewCertPool()
|
||||||
//nolint:gocritic
|
if scheme != HTTPS {
|
||||||
if config.CrowdsecLapiScheme != HTTPS {
|
log.Debug("getTLSConfigCrowdsec:" + prefix + "Scheme https:no")
|
||||||
log.Debug("getTLSConfigCrowdsec:CrowdsecLapiScheme https:no")
|
|
||||||
return tlsConfig, nil
|
return tlsConfig, nil
|
||||||
} else if config.CrowdsecLapiTLSInsecureVerify {
|
}
|
||||||
|
//nolint:nestif
|
||||||
|
if insecureVerify {
|
||||||
tlsConfig.InsecureSkipVerify = true
|
tlsConfig.InsecureSkipVerify = true
|
||||||
log.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSInsecureVerify tlsInsecure:true")
|
log.Debug("getTLSConfigCrowdsec:" + prefix + "TLSInsecureVerify tlsInsecure:true")
|
||||||
// If we return here and still want to use client auth this won't work
|
// If we return here and still want to use client auth this won't work
|
||||||
// return tlsConfig, nil
|
// return tlsConfig, nil
|
||||||
} else {
|
} else {
|
||||||
certAuthority, err := GetVariable(config, "CrowdsecLapiTLSCertificateAuthority")
|
certAuthority, err := GetVariable(config, prefix+"TLSCertificateAuthority")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -440,17 +454,16 @@ func GetTLSConfigCrowdsec(config *Config, log *logger.Log) (*tls.Config, error)
|
|||||||
if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(certAuthority)) {
|
if !tlsConfig.RootCAs.AppendCertsFromPEM([]byte(certAuthority)) {
|
||||||
// here we return because if CrowdsecLapiTLSInsecureVerify is false
|
// here we return because if CrowdsecLapiTLSInsecureVerify is false
|
||||||
// and CA not load, we can't communicate with https
|
// and CA not load, we can't communicate with https
|
||||||
return nil, errors.New("getTLSConfigCrowdsec:cannot load CA and verify cert is enabled")
|
return nil, errors.New("getTLSConfigCrowdsec:" + prefix + "cannot load CA and verify cert is enabled")
|
||||||
}
|
}
|
||||||
log.Debug("getTLSConfigCrowdsec:CrowdsecLapiTLSCertificateAuthority CA added successfully")
|
log.Debug("getTLSConfigCrowdsec:" + prefix + "TLSCertificateAuthority CA added successfully")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
certBouncer, err := GetVariable(config, prefix+"TLSCertificateBouncer")
|
||||||
certBouncer, err := GetVariable(config, "CrowdsecLapiTLSCertificateBouncer")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
certBouncerKey, err := GetVariable(config, "CrowdsecLapiTLSCertificateBouncerKey")
|
certBouncerKey, err := GetVariable(config, prefix+"TLSCertificateBouncerKey")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -465,3 +478,14 @@ func GetTLSConfigCrowdsec(config *Config, log *logger.Log) (*tls.Config, error)
|
|||||||
|
|
||||||
return tlsConfig, nil
|
return tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTLSConfigCrowdsec get TLS config from Config.
|
||||||
|
func GetTLSConfigCrowdsec(config *Config, log *logger.Log, isAppsec bool) (*tls.Config, error) {
|
||||||
|
var prefix string
|
||||||
|
if isAppsec && config.CrowdsecAppsecScheme != "" {
|
||||||
|
prefix = "CrowdsecAppsec"
|
||||||
|
return getTLSConfig(config, log, prefix, config.CrowdsecAppsecScheme, config.CrowdsecAppsecTLSInsecureVerify)
|
||||||
|
}
|
||||||
|
prefix = "CrowdsecLapi"
|
||||||
|
return getTLSConfig(config, log, prefix, config.CrowdsecLapiScheme, config.CrowdsecLapiTLSInsecureVerify)
|
||||||
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ func Test_GetTLSConfigCrowdsec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := GetTLSConfigCrowdsec(tt.args.config, logger.New("INFO", ""))
|
got, err := GetTLSConfigCrowdsec(tt.args.config, logger.New("INFO", ""), false)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("getTLSConfigCrowdsec() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("getTLSConfigCrowdsec() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user