From 892909b9b8bd6da9eb91a990aa0dd46bd1e467ba Mon Sep 17 00:00:00 2001 From: maxlerebourg Date: Sun, 21 Dec 2025 21:52:19 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix=20start=20up=20config=20erro?= =?UTF-8?q?r=20for=20appsec=20and=20review=20doc=20for=20appsec=20tls=20?= =?UTF-8?q?=20(#300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fix start up config error for appsec * :doc: add documentation on appsec variables and missing conf parameter * :bento: fix lint * :bento: fix lint * :bento: fix lint * :bento: fix after lot of tests * update exemple tls with new variables tested * fix exemple appsec with release and not localplugin --------- Co-authored-by: mhx --- Makefile | 2 +- README.md | 33 ++++- bouncer.go | 33 +++-- docker-compose.local.yml | 7 +- ....appsec-enabled.yml => docker-compose.yml} | 4 +- examples/tls-auth/README.md | 36 +++-- examples/tls-auth/config/acquis.yaml | 9 ++ examples/tls-auth/docker-compose.yml | 34 +++-- examples/tls-auth/gencerts.sh | 4 +- pkg/configuration/configuration.go | 131 +++++++++--------- 10 files changed, 180 insertions(+), 113 deletions(-) rename examples/appsec-enabled/{docker-compose.appsec-enabled.yml => docker-compose.yml} (96%) diff --git a/Makefile b/Makefile index 5894fde..4785399 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ clean_all_docker: docker compose -f examples/redis-cache/docker-compose.yml down --remove-orphans docker compose -f examples/trusted-ips/docker-compose.yml down --remove-orphans docker compose -f examples/tls-auth/docker-compose.yml down --remove-orphans - docker compose -f examples/appsec-enabled/docker-compose.appsec-enabled.yml down --remove-orphans + docker compose -f examples/appsec-enabled/docker-compose.yml down --remove-orphans docker compose -f examples/captcha/docker-compose.yml down --remove-orphans docker compose -f examples/custom-captcha/docker-compose.yml down --remove-orphans docker compose -f examples/custom-ban-page/docker-compose.yml down --remove-orphans diff --git a/README.md b/README.md index 2a54171..fdda774 100644 --- a/README.md +++ b/README.md @@ -310,17 +310,16 @@ make run ### Note > [!IMPORTANT] -> Some of the behaviours and configuration parameters are shared globally across *all* crowdsec middlewares even if you declare different middlewares with different settings. +> Some of the behaviours and configuration parameters are shared globally across _all_ crowdsec middlewares even if you declare different middlewares with different settings. > > **Cache is shared by all services**: This means if an IP is banned, all services which are protected by an instance of the plugin will deny requests from that IP > > If you define different caches for different middlewares, only the first one to be instantiated will be bound to the crowdsec stream. > -> Overall, this middleware is designed in such a way that **only one instance of the plugin is *possible*.** You can have multiple crowdsec middlewares in the same cluster, the key parameters must be aligned (MetricsUpdateIntervalSeconds, CrowdsecMode, CrowdsecAppsecEnabled, etc.) +> Overall, this middleware is designed in such a way that **only one instance of the plugin is _possible_.** You can have multiple crowdsec middlewares in the same cluster, the key parameters must be aligned (MetricsUpdateIntervalSeconds, CrowdsecMode, CrowdsecAppsecEnabled, etc.) > [!WARNING] -> **Appsec maximum body limit is defaulted to 10MB** -> *Be careful when you upgrade to >1.4.x* +> **Appsec maximum body limit is defaulted to 10MB** > _Be careful when you upgrade to >1.4.x_ ### Variables @@ -351,7 +350,18 @@ make run - CrowdsecAppsecHost - string - default: "crowdsec:7422" - - Crowdsec Appsec Server available on which host and port. The scheme will be handled by the CrowdsecLapiScheme var. + - Crowdsec Appsec Server available on which host and port. +- CrowdsecAppsecTlsInsecureVerify + - bool + - default: false + - Disable verification of certificate presented by Appsec +- CrowdsecAppsecTlsCertificateAuthority + - string + - default: "" + - PEM-encoded Certificate Authority of Appsec +- CrowdsecAppsecScheme + - string + - default: value of `CrowdsecLapiScheme`, expected values are: `http`, `https` - CrowdsecAppsecPath - string - default: "/" @@ -368,6 +378,10 @@ make run - int64 - default: 10485760 (= 10MB) - Transmit only the first number of bytes to Crowdsec Appsec Server. +- CrowdsecAppsecKey + - string + - default: value of `CrowdsecLapiKey` + - Crowdsec AppSec key for the bouncer. - CrowdsecLapiScheme - string - default: `http`, expected values are: `http`, `https` @@ -614,7 +628,7 @@ http: #### Fill variable with value of file -`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. +`CrowdsecLapiTlsCertificateBouncerKey`, `CrowdsecLapiTlsCertificateBouncer`, `CrowdsecLapiTlsCertificateAuthority`, `CrowdsecAppsecTlsCertificateAuthority`, `CrowdsecCapiMachineId`, `CrowdsecCapiPassword`, `CrowdsecLapiKey`, `CrowdsecAppsecKey`, `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. Format is: @@ -677,6 +691,13 @@ Set the `crowdsecLapiScheme` to https. Crowdsec must be listening in HTTPS for this to work. Please see the [tls-auth example](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/blob/main/examples/tls-auth/README.md) or the official documentation: [docs.crowdsec.net/docs/local_api/tls_auth/](https://docs.crowdsec.net/docs/local_api/tls_auth/) +#### Use HTTPS to communicate with the Appsec + +To communicate with the Appsec in HTTPS you need to either accept any certificates by setting the `crowdsecAppsecTLSInsecureVerify` to true or add the CA used by the server certificate of Crowdsec using `crowdsecAppsecTLSCertificateAuthority` or `crowdsecAppsecTLSCertificateAuthorityFile`. +Set the `crowdsecAppsecScheme` to https. + +Currently AppSec does not support mTLS authentication for the AppSec Component. + #### Manually add an IP to the blocklist (for testing purposes) ```bash diff --git a/bouncer.go b/bouncer.go index 22d9173..3e0bc0c 100644 --- a/bouncer.go +++ b/bouncer.go @@ -134,17 +134,23 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam serverChecker, _ := ip.NewChecker(log, config.ForwardedHeadersTrustedIPs) 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 + + var tlsAppsecConfig *tls.Config + if config.CrowdsecAppsecEnabled { + tlsAppsecConfig, err = configuration.GetTLSConfigCrowdsec(config, log, true) + if config.CrowdsecAppsecScheme == "" { + config.CrowdsecAppsecScheme = config.CrowdsecLapiScheme + } + 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.Info("New:crowdsecLapiKey fail to get CrowdsecAppsecKey and no client certificate setup " + errAppsecKey.Error()) + } + config.CrowdsecAppsecKey = apiAppsecKey } - 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 crowdsecStreamRoute := "" @@ -155,7 +161,6 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam config.CrowdsecLapiScheme = configuration.HTTPS config.CrowdsecLapiHost = crowdsecCapiHost config.CrowdsecLapiPath = "/" - config.CrowdsecAppsecEnabled = config.CrowdsecAppsecEnabled && config.CrowdsecAppsecScheme != "" config.UpdateIntervalSeconds = 7200 // 2 hours crowdsecStreamRoute = crowdsecCapiStreamRoute crowdsecHeader = crowdsecCapiHeader @@ -173,6 +178,9 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam return nil, errKey } config.CrowdsecLapiKey = apiKey + if config.CrowdsecAppsecKey == "" { + config.CrowdsecAppsecKey = apiKey + } } var banTemplate *htmltemplate.Template @@ -374,6 +382,9 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } else { value, err := handleNoStreamCache(bouncer, remoteIP) + if err != nil { + bouncer.log.Debug("handleNoStreamCache:crowdsecQuery " + err.Error()) + } if value == cache.NoBannedValue { bouncer.handleNextServeHTTP(rw, req, remoteIP) } else { diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 040496a..a746d4e 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -1,6 +1,6 @@ services: traefik: - image: "traefik:v3.0.0" + image: "traefik:v3.5.0" container_name: "traefik" restart: unless-stopped command: @@ -16,8 +16,8 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - logs-local:/var/log/traefik - - './ban.html:/ban.html:ro' - - './captcha.html:/captcha.html:ro' + - "./ban.html:/ban.html:ro" + - "./captcha.html:/captcha.html:ro" - ./:/plugins-local/src/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin ports: - 8000:80 @@ -52,6 +52,7 @@ services: - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsecenabled=true" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecmode=stream" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapikey=40796d93c2958f9e58345514e67740e5=" + - "traefik.http.middlewares.crowdsec.plugin.bouncer.ForwardedHeadersTrustedIPs=172.21.0.1/8" bar2: image: traefik/whoami diff --git a/examples/appsec-enabled/docker-compose.appsec-enabled.yml b/examples/appsec-enabled/docker-compose.yml similarity index 96% rename from examples/appsec-enabled/docker-compose.appsec-enabled.yml rename to examples/appsec-enabled/docker-compose.yml index 6ee6372..5834f2b 100644 --- a/examples/appsec-enabled/docker-compose.appsec-enabled.yml +++ b/examples/appsec-enabled/docker-compose.yml @@ -1,6 +1,6 @@ services: traefik: - image: "traefik:v3.0.0" + image: "traefik:v3.5.0" container_name: "traefik" restart: unless-stopped command: @@ -13,7 +13,7 @@ services: - "--entrypoints.web.address=:80" - "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" - - "--experimental.plugins.bouncer.version=v1.3.0" + - "--experimental.plugins.bouncer.version=v1.5.0" # - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro diff --git a/examples/tls-auth/README.md b/examples/tls-auth/README.md index dac4d03..7f8ba6e 100644 --- a/examples/tls-auth/README.md +++ b/examples/tls-auth/README.md @@ -1,7 +1,9 @@ # Example + ## Using https communication and tls authentication with Crowdsec ##### Summary + This example demonstrates the use of https between the Traefik plugin and the Crowdsec LAPI. It is possible to communicate with the LAPI in https and still authenticate with API key. @@ -17,7 +19,9 @@ In that case the setting **crowdsecLapiTLSInsecureVerify** must be set to true. It is recommended to validate the certificate presented by Crowdsec LAPI using the Certificate Authority which created it. You can provide the Certificate Authority using: -* A file path readable by Traefik + +- A file path readable by Traefik + ```yaml http: middlewares: @@ -26,9 +30,11 @@ http: bouncer: crowdsecLapiTlsCertificateAuthorityFile: /etc/traefik/certs/crowdsecCA.pem ``` -* The PEM encoded certificate as a text variable + +- The PEM encoded certificate as a text variable In the static file configuration of Traefik + ```yaml http: middlewares: @@ -36,15 +42,17 @@ http: plugin: bouncer: crowdsecLapiTlsCertificateAuthority: |- - -----BEGIN CERTIFICATE----- - MIIEBzCCAu+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZQxCzAJBgNVBAYTAlVT - MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK - ... - C6qNieSwcvWL7C03ri0DefTQMY54r5wP33QU5hJ71JoaZI3YTeT0Nf+NRL4hM++w - Q0veeNzBQXg1f/JxfeA39IDIX1kiCf71tGlT - -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIEBzCCAu+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZQxCzAJBgNVBAYTAlVT + MRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK + ... + C6qNieSwcvWL7C03ri0DefTQMY54r5wP33QU5hJ71JoaZI3YTeT0Nf+NRL4hM++w + Q0veeNzBQXg1f/JxfeA39IDIX1kiCf71tGlT + -----END CERTIFICATE----- ``` + In a dynamic configuration of a provider (ex docker) as a Label + ```yaml services: whoami-foo: @@ -71,26 +79,34 @@ The service `whoami-foo` will authenticate with an **API key** over HTTPS after The service `whoami-bar` will authenticate with a **client certificate** signed by the CA. Access to a route that communicate via https and authenticate with API-key: + ``` curl http://localhost:8000/foo ``` + Access to a route that communicate via https and authenticate with a client certificate: + ``` curl http://localhost:8000/bar ``` + Access to the traefik dashboard + ``` curl http://localhost:8080/dashboard/#/ ``` To play the demo environnement run: + ```bash make run_tlsauth ``` Note: -> Traefik need to be restarted if certificates are regenerated after his launch + +> Traefik need to be restarted if certificates are regenerated after his launch, crowdsec also ## 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. diff --git a/examples/tls-auth/config/acquis.yaml b/examples/tls-auth/config/acquis.yaml index 5d52554..d48a16b 100644 --- a/examples/tls-auth/config/acquis.yaml +++ b/examples/tls-auth/config/acquis.yaml @@ -2,3 +2,12 @@ filenames: - /var/log/traefik/access.log labels: type: traefik +--- +listen_addr: 0.0.0.0:7422 +appsec_config: crowdsecurity/virtual-patching +name: myAppSecComponent +source: appsec +labels: + type: appsec +cert_file: /etc/crowdsec/certs/server.pem +key_file: /etc/crowdsec/certs/server-key.pem \ No newline at end of file diff --git a/examples/tls-auth/docker-compose.yml b/examples/tls-auth/docker-compose.yml index 80bfc70..d1d6c48 100644 --- a/examples/tls-auth/docker-compose.yml +++ b/examples/tls-auth/docker-compose.yml @@ -1,6 +1,6 @@ services: traefik: - image: "traefik:v3.0.0" + image: "traefik:v3.5.0" container_name: "traefik" restart: unless-stopped command: @@ -13,15 +13,13 @@ services: - "--entrypoints.web.address=:80" - "--experimental.plugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" - - "--experimental.plugins.bouncer.version=v1.3.0" + - "--experimental.plugins.bouncer.version=v1.5.0" # - "--experimental.localplugins.bouncer.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - - ./LAPIKEY:/etc/traefik/LAPIKEY:ro - logs-tls-auth:/var/log/traefik - crowdsec-certs-tls-auth:/etc/traefik/crowdsec-certs # - ./../../:/plugins-local/src/github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin - ports: - 8000:80 - 8080:8080 @@ -29,7 +27,7 @@ services: - crowdsec - gencert -# Use HTTPS scheme but with lapikey authentication + # Use HTTPS scheme but with lapikey authentication # whoami-foo: # image: traefik/whoami # container_name: "simple-service-foo" @@ -38,7 +36,7 @@ services: # - "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@docker" + # - "traefik.http.routers.router-foo.middlewares=crowdsec@docker" # - "traefik.http.services.service-foo.loadbalancer.server.port=80" # - "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true" # - "traefik.http.middlewares.crowdsec.plugin.bouncer.loglevel=DEBUG" @@ -46,34 +44,41 @@ services: # - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapischeme=https" # - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapiTLSCertificateAuthorityFile=/etc/traefik/crowdsec-certs/inter.pem" -# Use HTTPS scheme with TLS cert authentication + # Use HTTPS scheme with TLS cert authentication whoami-bar: image: traefik/whoami container_name: "simple-service-bar" restart: unless-stopped labels: - "traefik.enable=true" - - "traefik.http.routers.router-bar.rule=Path(`/bar`)" + - "traefik.http.routers.router-bar.rule=PathPrefix(`/bar`)" - "traefik.http.routers.router-bar.entrypoints=web" - "traefik.http.routers.router-bar.middlewares=crowdsec@docker" - "traefik.http.services.service-bar.loadbalancer.server.port=80" - "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true" - "traefik.http.middlewares.crowdsec.plugin.bouncer.loglevel=DEBUG" + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecMode=none" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapischeme=https" + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsecscheme=https" + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecAppsecTLSCertificateAuthorityFile=/etc/traefik/crowdsec-certs/inter.pem" + + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapikey=40796d93c2958f9e58345514e67740e5=" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapiTLSCertificateAuthorityFile=/etc/traefik/crowdsec-certs/inter.pem" - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapiTLSCertificateBouncerFile=/etc/traefik/crowdsec-certs/bouncer.pem" - - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapiTLSCertificateBouncerKeyFile=/etc/traefik/crowdsec-certs/bouncer-key.pem" - + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecLapiTLSCertificateBouncerKeyFile=/etc/traefik/crowdsec-certs/bouncer-key.pem" + # Enable AppSec + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsecenabled=true" + # Define AppSec host and port informations + - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422" crowdsec: - image: crowdsecurity/crowdsec:v1.6.1-2 + image: crowdsecurity/crowdsec:latest container_name: "crowdsec" restart: unless-stopped environment: - COLLECTIONS: crowdsecurity/traefik CUSTOM_HOSTNAME: crowdsec # whoami-foo is authenticating with api key over https # whoami-bar is authenticating with tls cert over https - BOUNCER_KEY_TRAEFIK_FOO: 40796d93c2958f9e58345514e67740e5 + BOUNCER_KEY_TRAEFIK_FOO: 40796d93c2958f9e58345514e67740e5= LOCAL_API_URL: https://127.0.0.1:8080 USE_TLS: "true" CERT_FILE: "/etc/crowdsec/certs/server.pem" @@ -88,6 +93,7 @@ services: # DISABLE_AGENT: "true" # Disabled for the examples DISABLE_ONLINE_API: "true" + COLLECTIONS: crowdsecurity/traefik crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules volumes: - ./config/acquis.yaml:/etc/crowdsec/acquis.yaml # - ./config/config.yaml:/etc/crowdsec/config_local.yaml @@ -100,7 +106,7 @@ services: - "traefik.enable=false" depends_on: - gencert - + gencert: build: . volumes: diff --git a/examples/tls-auth/gencerts.sh b/examples/tls-auth/gencerts.sh index 4003595..67f9521 100644 --- a/examples/tls-auth/gencerts.sh +++ b/examples/tls-auth/gencerts.sh @@ -1,6 +1,8 @@ #!/bin/bash -stdout=/out/res.log +if [ -f "/out/inter-key.pem" ]; then + exit 0 +fi cfssl gencert --initca /in/ca.json 2>${stdout} | cfssljson --bare "/out/ca" && \ # Generate an intermediate certificate that will be used to sign the client certificates cfssl gencert --initca /in/intermediate.json 2>${stdout} | cfssljson --bare "/out/inter" && \ diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go index 5becb98..5051cfa 100644 --- a/pkg/configuration/configuration.go +++ b/pkg/configuration/configuration.go @@ -42,71 +42,72 @@ const ( // Config the plugin configuration. type Config struct { - Enabled bool `json:"enabled,omitempty"` - LogLevel string `json:"logLevel,omitempty"` - LogFilePath string `json:"logFilePath,omitempty"` - CrowdsecMode string `json:"crowdsecMode,omitempty"` - CrowdsecAppsecEnabled bool `json:"crowdsecAppsecEnabled,omitempty"` - CrowdsecAppsecScheme string `json:"crowdsecAppsecScheme,omitempty"` - CrowdsecAppsecHost string `json:"crowdsecAppsecHost,omitempty"` - CrowdsecAppsecPath string `json:"crowdsecAppsecPath,omitempty"` - CrowdsecAppsecKey string `json:"crowdsecAppsecKey,omitempty"` - CrowdsecAppsecKeyFile string `json:"crowdsecAppsecKeyFile,omitempty"` - CrowdsecAppsecTLSInsecureVerify bool `json:"crowdsecAppsecTlsInsecureVerify,omitempty"` - CrowdsecAppsecTLSCertificateAuthority string `json:"crowdsecAppsecTlsCertificateAuthority,omitempty"` - CrowdsecAppsecTLSCertificateAuthorityFile string `json:"crowdsecAppsecTlsCertificateAuthorityFile,omitempty"` - CrowdsecAppsecTLSCertificateBouncer string `json:"crowdsecAppsecTlsCertificateBouncer,omitempty"` - CrowdsecAppsecTLSCertificateBouncerFile string `json:"crowdsecAppsecTlsCertificateBouncerFile,omitempty"` - CrowdsecAppsecTLSCertificateBouncerKey string `json:"crowdsecAppsecTlsCertificateBouncerKey,omitempty"` - CrowdsecAppsecFailureBlock bool `json:"crowdsecAppsecFailureBlock,omitempty"` - CrowdsecAppsecUnreachableBlock bool `json:"crowdsecAppsecUnreachableBlock,omitempty"` - CrowdsecAppsecBodyLimit int64 `json:"crowdsecAppsecBodyLimit,omitempty"` - CrowdsecLapiScheme string `json:"crowdsecLapiScheme,omitempty"` - CrowdsecLapiHost string `json:"crowdsecLapiHost,omitempty"` - CrowdsecLapiPath string `json:"crowdsecLapiPath,omitempty"` - CrowdsecLapiKey string `json:"crowdsecLapiKey,omitempty"` - CrowdsecLapiKeyFile string `json:"crowdsecLapiKeyFile,omitempty"` - CrowdsecLapiTLSInsecureVerify bool `json:"crowdsecLapiTlsInsecureVerify,omitempty"` - CrowdsecLapiTLSCertificateAuthority string `json:"crowdsecLapiTlsCertificateAuthority,omitempty"` - CrowdsecLapiTLSCertificateAuthorityFile string `json:"crowdsecLapiTlsCertificateAuthorityFile,omitempty"` - CrowdsecLapiTLSCertificateBouncer string `json:"crowdsecLapiTlsCertificateBouncer,omitempty"` - CrowdsecLapiTLSCertificateBouncerFile string `json:"crowdsecLapiTlsCertificateBouncerFile,omitempty"` - CrowdsecLapiTLSCertificateBouncerKey string `json:"crowdsecLapiTlsCertificateBouncerKey,omitempty"` - CrowdsecLapiTLSCertificateBouncerKeyFile string `json:"crowdsecLapiTlsCertificateBouncerKeyFile,omitempty"` - CrowdsecCapiMachineID string `json:"crowdsecCapiMachineId,omitempty"` - CrowdsecCapiMachineIDFile string `json:"crowdsecCapiMachineIdFile,omitempty"` - CrowdsecCapiPassword string `json:"crowdsecCapiPassword,omitempty"` - CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"` - CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"` - UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"` - MetricsUpdateIntervalSeconds int64 `json:"metricsUpdateIntervalSeconds,omitempty"` - UpdateMaxFailure int64 `json:"updateMaxFailure,omitempty"` - DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"` - RemediationStatusCode int `json:"remediationStatusCode,omitempty"` - HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"` - TraceHeadersCustomName string `json:"traceHeadersCustomName,omitempty"` - RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"` - ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"` - ForwardedHeadersTrustedIPs []string `json:"forwardedHeadersTrustedIps,omitempty"` - ClientTrustedIPs []string `json:"clientTrustedIps,omitempty"` - RedisCacheEnabled bool `json:"redisCacheEnabled,omitempty"` - RedisCacheHost string `json:"redisCacheHost,omitempty"` - RedisCachePassword string `json:"redisCachePassword,omitempty"` - RedisCachePasswordFile string `json:"redisCachePasswordFile,omitempty"` - RedisCacheDatabase string `json:"redisCacheDatabase,omitempty"` - RedisCacheUnreachableBlock bool `json:"redisCacheUnreachableBlock,omitempty"` - BanHTMLFilePath string `json:"banHtmlFilePath,omitempty"` - CaptchaHTMLFilePath string `json:"captchaHtmlFilePath,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"` + Enabled bool `json:"enabled,omitempty"` + LogLevel string `json:"logLevel,omitempty"` + LogFilePath string `json:"logFilePath,omitempty"` + CrowdsecMode string `json:"crowdsecMode,omitempty"` + CrowdsecAppsecEnabled bool `json:"crowdsecAppsecEnabled,omitempty"` + CrowdsecAppsecScheme string `json:"crowdsecAppsecScheme,omitempty"` + CrowdsecAppsecHost string `json:"crowdsecAppsecHost,omitempty"` + CrowdsecAppsecPath string `json:"crowdsecAppsecPath,omitempty"` + CrowdsecAppsecKey string `json:"crowdsecAppsecKey,omitempty"` + CrowdsecAppsecKeyFile string `json:"crowdsecAppsecKeyFile,omitempty"` + CrowdsecAppsecTLSInsecureVerify bool `json:"crowdsecAppsecTlsInsecureVerify,omitempty"` + CrowdsecAppsecTLSCertificateAuthority string `json:"crowdsecAppsecTlsCertificateAuthority,omitempty"` + CrowdsecAppsecTLSCertificateAuthorityFile string `json:"crowdsecAppsecTlsCertificateAuthorityFile,omitempty"` + CrowdsecAppsecTLSCertificateBouncer string `json:"crowdsecAppsecTlsCertificateBouncer,omitempty"` + CrowdsecAppsecTLSCertificateBouncerFile string `json:"crowdsecAppsecTlsCertificateBouncerFile,omitempty"` + CrowdsecAppsecTLSCertificateBouncerKey string `json:"crowdsecAppsecTlsCertificateBouncerKey,omitempty"` + CrowdsecAppsecTLSCertificateBouncerKeyFile string `json:"crowdsecAppsecTlsCertificateBouncerKeyFile,omitempty"` + CrowdsecAppsecFailureBlock bool `json:"crowdsecAppsecFailureBlock,omitempty"` + CrowdsecAppsecUnreachableBlock bool `json:"crowdsecAppsecUnreachableBlock,omitempty"` + CrowdsecAppsecBodyLimit int64 `json:"crowdsecAppsecBodyLimit,omitempty"` + CrowdsecLapiScheme string `json:"crowdsecLapiScheme,omitempty"` + CrowdsecLapiHost string `json:"crowdsecLapiHost,omitempty"` + CrowdsecLapiPath string `json:"crowdsecLapiPath,omitempty"` + CrowdsecLapiKey string `json:"crowdsecLapiKey,omitempty"` + CrowdsecLapiKeyFile string `json:"crowdsecLapiKeyFile,omitempty"` + CrowdsecLapiTLSInsecureVerify bool `json:"crowdsecLapiTlsInsecureVerify,omitempty"` + CrowdsecLapiTLSCertificateAuthority string `json:"crowdsecLapiTlsCertificateAuthority,omitempty"` + CrowdsecLapiTLSCertificateAuthorityFile string `json:"crowdsecLapiTlsCertificateAuthorityFile,omitempty"` + CrowdsecLapiTLSCertificateBouncer string `json:"crowdsecLapiTlsCertificateBouncer,omitempty"` + CrowdsecLapiTLSCertificateBouncerFile string `json:"crowdsecLapiTlsCertificateBouncerFile,omitempty"` + CrowdsecLapiTLSCertificateBouncerKey string `json:"crowdsecLapiTlsCertificateBouncerKey,omitempty"` + CrowdsecLapiTLSCertificateBouncerKeyFile string `json:"crowdsecLapiTlsCertificateBouncerKeyFile,omitempty"` + CrowdsecCapiMachineID string `json:"crowdsecCapiMachineId,omitempty"` + CrowdsecCapiMachineIDFile string `json:"crowdsecCapiMachineIdFile,omitempty"` + CrowdsecCapiPassword string `json:"crowdsecCapiPassword,omitempty"` + CrowdsecCapiPasswordFile string `json:"crowdsecCapiPasswordFile,omitempty"` + CrowdsecCapiScenarios []string `json:"crowdsecCapiScenarios,omitempty"` + UpdateIntervalSeconds int64 `json:"updateIntervalSeconds,omitempty"` + MetricsUpdateIntervalSeconds int64 `json:"metricsUpdateIntervalSeconds,omitempty"` + UpdateMaxFailure int64 `json:"updateMaxFailure,omitempty"` + DefaultDecisionSeconds int64 `json:"defaultDecisionSeconds,omitempty"` + RemediationStatusCode int `json:"remediationStatusCode,omitempty"` + HTTPTimeoutSeconds int64 `json:"httpTimeoutSeconds,omitempty"` + TraceHeadersCustomName string `json:"traceHeadersCustomName,omitempty"` + RemediationHeadersCustomName string `json:"remediationHeadersCustomName,omitempty"` + ForwardedHeadersCustomName string `json:"forwardedHeadersCustomName,omitempty"` + ForwardedHeadersTrustedIPs []string `json:"forwardedHeadersTrustedIps,omitempty"` + ClientTrustedIPs []string `json:"clientTrustedIps,omitempty"` + RedisCacheEnabled bool `json:"redisCacheEnabled,omitempty"` + RedisCacheHost string `json:"redisCacheHost,omitempty"` + RedisCachePassword string `json:"redisCachePassword,omitempty"` + RedisCachePasswordFile string `json:"redisCachePasswordFile,omitempty"` + RedisCacheDatabase string `json:"redisCacheDatabase,omitempty"` + RedisCacheUnreachableBlock bool `json:"redisCacheUnreachableBlock,omitempty"` + BanHTMLFilePath string `json:"banHtmlFilePath,omitempty"` + CaptchaHTMLFilePath string `json:"captchaHtmlFilePath,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 {