From 1860bbc9d62737bce2bfa17163d9cf1389601bb4 Mon Sep 17 00:00:00 2001 From: Sebastien Blot Date: Wed, 20 May 2026 10:20:20 +0200 Subject: [PATCH 1/2] waf: update doc for body handling --- crowdsec-docs/docs/appsec/configuration.md | 4 + crowdsec-docs/docs/appsec/hooks.md | 107 +++++++++++++----- crowdsec-docs/docs/appsec/rules_examples.md | 42 +++++++ .../docs/log_processor/data_sources/appsec.md | 6 + 4 files changed, 128 insertions(+), 31 deletions(-) diff --git a/crowdsec-docs/docs/appsec/configuration.md b/crowdsec-docs/docs/appsec/configuration.md index d26837fd3..2a62d46a2 100644 --- a/crowdsec-docs/docs/appsec/configuration.md +++ b/crowdsec-docs/docs/appsec/configuration.md @@ -168,6 +168,10 @@ inband_options: request_body_in_memory_limit: 1048576 ``` +:::note +`request_body_in_memory_limit` is a Coraza-level setting. It is distinct from the engine's overall maximum body size, which bounds how much of the body CrowdSec buffers before any rule runs (defaults to 10MB). See [Request body size handling](hooks.md#request-body-size-handling) to tune it. +::: + ### outofband_options > object diff --git a/crowdsec-docs/docs/appsec/hooks.md b/crowdsec-docs/docs/appsec/hooks.md index 95811bce4..32f58eb72 100644 --- a/crowdsec-docs/docs/appsec/hooks.md +++ b/crowdsec-docs/docs/appsec/hooks.md @@ -43,20 +43,22 @@ This hook is intended to be used to disable rules at loading (eg, to temporarily #### Available helpers -| Helper Name | Type | Description | -| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- | -| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | -| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | -| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | -| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | -| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | -| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | -| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | -| `LoadAPISchemaWithName` | `func(ref str, filename str)` | Load an OpenAPI schema from `/schemas/` and register it under `ref`. See [OpenAPI Schema Validation](api_validation.md). | -| `LoadAPISchemaWithOptions` | `func(ref str, filename str, opts map)` | Same as `LoadAPISchemaWithName` but accepts per-schema policy overrides (`on_route_not_found`, `on_method_not_allowed`). | -| `RegisterAPISchemaBodyDecoder` | `func(content_type str, decoder str)` | Enable a non-default body decoder for a Content-Type. See [available decoders](api_validation.md#body-decoders). | +| Helper Name | Type | Description | +| ------------------------------ | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | +| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | +| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | +| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | +| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | +| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | +| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | +| `LoadAPISchemaWithName` | `func(ref str, filename str)` | Load an OpenAPI schema from `/schemas/` and register it under `ref`. See [OpenAPI Schema Validation](api_validation.md). | +| `LoadAPISchemaWithOptions` | `func(ref str, filename str, opts map)` | Same as `LoadAPISchemaWithName` but accepts per-schema policy overrides (`on_route_not_found`, `on_method_not_allowed`). | +| `RegisterAPISchemaBodyDecoder` | `func(content_type str, decoder str)` | Enable a non-default body decoder for a Content-Type. See [available decoders](api_validation.md#body-decoders). | +| `SetMaxBodySize` | `func(size int)` | Set the maximum request body size (in bytes) buffered and inspected by the engine. Defaults to 10MB. See [Request body size handling](#request-body-size-handling) | +| `SetBodySizeExceededAction` | `func(action str)` | Set what happens when a request body exceeds the maximum size: `drop` (default), `partial`, or `allow`. See [Request body size handling](#request-body-size-handling) | ##### Example @@ -78,23 +80,24 @@ This hook is intended to be used to disable rules only for this particular reque #### Available helpers -| Helper Name | Type | Description | -| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- | -| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | -| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | -| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | -| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | -| `IsInBand` | `bool` | `true` if the request is in the in-band processing phase | -| `IsOutBand` | `bool` | `true` if the request is in the out-of-band processing phase | -| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | -| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | -| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | -| `req` | `http.Request` | Original HTTP request received by the remediation component | -| `DropRequest` | `func(reason str)` | Stop processing the request immediately and instruct the remediation component to block the request | -| `ValidateRequestWithSchema` | `func(ref str) bool` | Validate the current request against an OpenAPI schema previously loaded under `ref` (returns `true` on success). On failure, structured details are published to `hook_vars` (see [OpenAPI Schema Validation](api_validation.md#validation-result-variables)). | -| `hook_vars` | `map[string]string` | Per-request scratch space shared with later hooks and propagated to the resulting event. Helpers such as `ValidateRequestWithSchema` publish their results here. | +| Helper Name | Type | Description | +| --------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | +| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | +| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | +| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | +| `IsInBand` | `bool` | `true` if the request is in the in-band processing phase | +| `IsOutBand` | `bool` | `true` if the request is in the out-of-band processing phase | +| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | +| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | +| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | +| `req` | `http.Request` | Original HTTP request received by the remediation component | +| `DropRequest` | `func(reason str)` | Stop processing the request immediately and instruct the remediation component to block the request | +| `DisableBodyInspection` | `func()` | Skip body inspection for the current request (also bypasses the maximum body size check). See [Request body size handling](#request-body-size-handling) | +| `ValidateRequestWithSchema` | `func(ref str) bool` | Validate the current request against an OpenAPI schema previously loaded under `ref` (returns `true` on success). On failure, structured details are published to `hook_vars` (see [OpenAPI Schema Validation](api_validation.md#validation-result-variables)). | +| `hook_vars` | `map[string]string` | Per-request scratch space shared with later hooks and propagated to the resulting event. Helpers such as `ValidateRequestWithSchema` publish their results here. | #### Example @@ -216,6 +219,48 @@ on_match: When using `SetRemediation*` helpers, the only special value is `allow`: the remediation component won't block the request. Any other values (including `ban` and `captcha`) are transmitted as-is to the remediation component. +### Request body size handling + +Before the request body is handed over to the rules engine, the Application Security Component reads it into memory itself. To protect the engine from oversized requests, the body is bounded by a maximum size (defaults to **10MB**). + +This limit is independent from the Coraza-level [`request_body_in_memory_limit`](configuration.md#inband_options) option: it controls how much of the body CrowdSec buffers in the first place, before any rule is evaluated. + +You can tune this behavior from an `on_load` hook: + +- `SetMaxBodySize(size)` sets the maximum body size, in bytes. The value must be a positive integer. +- `SetBodySizeExceededAction(action)` controls what happens when a body exceeds the maximum size: + + | Action | Behavior | + | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | + | `drop` (default) | The request is blocked using the default remediation, without inspecting the body. | + | `partial` | The body is truncated to the maximum size and the kept portion is inspected. Content beyond the truncation point is discarded and will not match any rule. | + | `allow` | The body is not inspected and the request is allowed to proceed (other zones are still evaluated). | + +```yaml +name: crowdsecurity/my-appsec-config +default_remediation: ban +inband_rules: + - crowdsecurity/base-config +on_load: + - apply: + - SetMaxBodySize(20971520) # 20MB + - SetBodySizeExceededAction("partial") +``` + +#### `DisableBodyInspection` + +`DisableBodyInspection()` can be called from a `pre_eval` hook to skip body inspection for the current request only. When body inspection is disabled: + +- the request body is not read or processed, so body-based zones (`BODY_ARGS`, `RAW_BODY`, …) won't match; +- the maximum body size check is bypassed as well: a request that would otherwise be dropped for exceeding the limit is allowed through, because the operator has explicitly accepted that this body won't be processed. + +```yaml +pre_eval: + - filter: req.URL.Path startsWith "/upload" + apply: + - DisableBodyInspection() +``` + ### `req` object The `pre_eval`, `on_match` and `post_eval` hooks have access to a `req` variable that represents the HTTP request that was forwarded to the appsec. diff --git a/crowdsec-docs/docs/appsec/rules_examples.md b/crowdsec-docs/docs/appsec/rules_examples.md index 38c8ab05b..e5350d2b1 100644 --- a/crowdsec-docs/docs/appsec/rules_examples.md +++ b/crowdsec-docs/docs/appsec/rules_examples.md @@ -507,6 +507,29 @@ label=aaa\u0027%2b#request.get(\u0027.KEY_velocity.struts2.context\u0027).intern Hooks allow you to customize WAF behavior at different execution phases. This section demonstrates key hook capabilities organized by execution phase. +## Load Phase (on_load) + +Load hooks run once when the configuration is loaded, and are typically used to apply global settings. + +### 1. Tune Request Body Size Handling + +#### Description + +Change the maximum request body size buffered and inspected by the engine, and what happens when a request exceeds it. + +#### Hook Example + +```yaml +on_load: + - apply: + - SetMaxBodySize(20971520) # 20MB + - SetBodySizeExceededAction("partial") +``` + +#### Use Case + +Allow larger uploads on this configuration while still bounding memory usage, and inspect the first 20MB of oversized bodies instead of dropping the request outright. See [Request body size handling](hooks.md#request-body-size-handling) for the available actions (`drop`, `partial`, `allow`). + ## Pre-Evaluation Phase (pre_eval) Pre-evaluation hooks run before rules are evaluated, allowing you to modify rule behavior dynamically per request. @@ -617,6 +640,25 @@ pre_eval: Automatically block traffic from unwanted countries. +### 6. Disable Body Inspection for Specific Requests + +#### Description + +Skip request body inspection for the current request, for example on endpoints that legitimately receive large uploads. + +#### Hook Example + +```yaml +pre_eval: + - filter: req.URL.Path startsWith "/upload" + apply: + - DisableBodyInspection() +``` + +#### Use Case + +Avoid buffering and inspecting large file uploads on trusted endpoints. This also bypasses the [maximum body size check](hooks.md#request-body-size-handling), so requests exceeding the limit are allowed through instead of being dropped. + ## Post-Evaluation Phase (post_eval) Post-evaluation hooks run after rule evaluation is complete, primarily used for debugging and logging. diff --git a/crowdsec-docs/docs/log_processor/data_sources/appsec.md b/crowdsec-docs/docs/log_processor/data_sources/appsec.md index 8b38aae3d..0d783c409 100644 --- a/crowdsec-docs/docs/log_processor/data_sources/appsec.md +++ b/crowdsec-docs/docs/log_processor/data_sources/appsec.md @@ -57,6 +57,12 @@ Number of routines to use to process the requests. Defaults to 1. How long to cache the auth token for. Accepts value supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration). Defaults to 1m. +### `body_read_timeout` + +How long to wait for the remediation component to finish sending the request body before giving up and processing whatever was received. Accepts value supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration). +Set to `0` to disable the timeout. +Defaults to 1s. + ### `cert_file` Path to the cert file to allow HTTPS communication between the remediation component and the appsec component. From fead6e61afe2266c7782b04fc88f4734f339baea Mon Sep 17 00:00:00 2001 From: Sebastien Blot Date: Wed, 20 May 2026 10:20:27 +0200 Subject: [PATCH 2/2] sync doc --- .../version-v1.7/appsec/api_validation.md | 233 ++++++++ .../version-v1.7/appsec/configuration.md | 4 + .../version-v1.7/appsec/hooks.md | 102 +++- .../version-v1.7/appsec/intro.md | 6 + .../appsec/quickstart/envoy-gateway.mdx | 499 ++++++++++++++++++ .../appsec/quickstart/general.mdx | 7 +- .../appsec/quickstart/haproxy_spoa.mdx | 131 ++--- .../appsec/quickstart/nginx-ingress.mdx | 6 +- .../appsec/quickstart/nginxopenresty.mdx | 294 +++-------- .../appsec/quickstart/npmplus.mdx | 234 +++----- .../appsec/quickstart/traefik.mdx | 6 +- .../appsec/quickstart/wordpress.mdx | 317 +++-------- .../version-v1.7/appsec/rules_deploy.md | 10 +- .../version-v1.7/appsec/rules_examples.md | 42 ++ .../configuration/network_management.md | 4 + .../getting_started/sdk_intro.mdx | 6 +- .../versioned_docs/version-v1.7/intro.mdx | 2 +- .../version-v1.7/local_api/database.md | 2 +- .../log_processor/data_sources/appsec.md | 6 + 19 files changed, 1141 insertions(+), 770 deletions(-) create mode 100644 crowdsec-docs/versioned_docs/version-v1.7/appsec/api_validation.md create mode 100644 crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/envoy-gateway.mdx diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/api_validation.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/api_validation.md new file mode 100644 index 000000000..0f118b615 --- /dev/null +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/api_validation.md @@ -0,0 +1,233 @@ +--- +id: api_validation +title: OpenAPI Schema Validation +sidebar_position: 5 +--- + +The Application Security Component can validate incoming HTTP requests against an [OpenAPI 3](https://swagger.io/specification/) schema you provide. Requests that do not conform to the schema (unknown route, unexpected method, missing or malformed parameters, invalid request body, missing/invalid authentication credentials, …) can be rejected before they ever reach the protected application. + +This is a positive-security model layered on top of the negative-security model implemented by the WAF rules: instead of describing what an attacker looks like, you describe what a valid client looks like and reject everything else. + +## How it works + +Schema validation is exposed through the [hooks](hooks.md) system: + +- An `on_load` hook loads one or more OpenAPI schemas at startup, each under a short string `ref`. +- A `pre_eval` hook calls `ValidateRequestWithSchema(ref)` to validate the current request. The function returns `true` when the request is valid, `false` otherwise. +- When validation fails, structured details about the failure are published to `hook_vars` so the same hook (or a later one) can build a meaningful drop reason, enrich an event, etc. + +## Storing schemas + +Schemas are loaded from the `schemas/` subdirectory of the CrowdSec [`data_dir`](/configuration/crowdsec_configuration.md#data_dir) (typically `/var/lib/crowdsec/data/schemas/`). + +Filenames passed to the loader **must be relative** to that directory. + +``` +/var/lib/crowdsec/data/schemas/ +├── users-api.yaml +└── billing-api.yaml +``` + +OpenAPI 3.0 and Swagger schemas in YAML or JSON are both accepted. + +## Loading schemas (`on_load`) + +Loading is done from an `on_load` hook using one of two helpers: + +| Helper | Description | +| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| `LoadAPISchemaWithName(ref str, filename str)` | Load `/schemas/` and register it under `ref`, with default policies. | +| `LoadAPISchemaWithOptions(ref str, filename str, opts map)` | Same as above, but lets you override per-schema policies (see below). | +| `RegisterAPISchemaBodyDecoder(content_type str, decoder str)` | Enable a non-default body decoder for a given Content-Type (see below). | + +`ref` is an arbitrary string you choose; you will use it later in `pre_eval` to refer to this schema. A schema name cannot be loaded twice. + +```yaml +name: custom/my-appsec-config +inband_rules: + - crowdsecurity/base-config +on_load: + - apply: + - LoadAPISchemaWithName("users_api", "users-api.yaml") + - LoadAPISchemaWithName("billing_api", "billing-api.yaml") +``` + +If the schema file is missing, malformed, or not a valid OpenAPI 3 document, the datasource will fail to start and log the underlying error. + +### Schema options + +`LoadAPISchemaWithOptions` accepts the following keys, all strings: + +| Key | Values | Default | Effect | +| -------------------------------- | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `on_route_not_found` | `drop` / `ignore` | `drop` | What to do when no path in the schema matches the request URL. | +| `on_method_not_allowed` | `drop` / `ignore` | `drop` | What to do when a path matches but the method does not (e.g. schema only declares `GET`, request is `POST`). | +| `on_unsupported_security_scheme` | `drop` / `ignore` | `drop` | What to do when an unsupported security schema is encountered (`openid`, `oauth2`). If `ignore`, the security schema will not be validated when checking a request | + +`drop` (the default) treats the unmatched route as a validation failure — `ValidateRequestWithSchema` returns `false` and the validation error is surfaced via `hook_vars`. `ignore` lets the request through the validator without inspection (the function returns `true`), which is useful when your schema only covers a subset of your API. + +```yaml +on_load: + - apply: + - > + LoadAPISchemaWithOptions("public_api", "public-api.yaml", { + "on_route_not_found": "ignore", + "on_method_not_allowed": "drop", + }) +``` + +### Body decoders + +The validator uses the request `Content-Type` to pick a decoder for the body. By default, only the following Content-Types are decoded: + +- `application/json` and the JSON variants `application/json-patch+json`, `application/merge-patch+json`, `application/ld+json`, `application/hal+json`, `application/vnd.api+json`, `application/problem+json` +- `application/x-www-form-urlencoded` +- `multipart/form-data` + +A request whose Content-Type is not in this list will fail validation if the matching operation in the schema declares a request body. + +To enable validation of additional Content-Types, register a decoder from `on_load`: + +```yaml +on_load: + - apply: + - RegisterAPISchemaBodyDecoder("application/yaml", "yaml") + - RegisterAPISchemaBodyDecoder("text/csv", "csv") +``` + +Available decoder names: + +| Decoder | Use for | +| ------------ | ----------------------------------------------------- | +| `json` | JSON payloads | +| `urlencoded` | `application/x-www-form-urlencoded` | +| `multipart` | `multipart/form-data` | +| `yaml` | YAML payloads | +| `csv` | CSV payloads | +| `plain` | `text/plain` | +| `file` | Raw binary uploads (`application/octet-stream`, etc.) | + +:::warning +Body decoders are registered process-wide. If you run several AppSec datasources in the same CrowdSec process, they share the same set of registered decoders. +::: + +## Validating requests (`pre_eval`) + +In a `pre_eval` hook, call `ValidateRequestWithSchema(ref)` with the `ref` you used at load time. It returns `true` if the request matches the schema, `false` otherwise. + +| Helper | Type | Description | +| --------------------------- | -------------------- | -------------------------------------------------------------------------------------------------- | +| `ValidateRequestWithSchema` | `func(ref str) bool` | Validate the current request against the schema registered under `ref`. Returns `true` on success. | + +A typical pattern is to fail closed — on validation failure, drop the request and use the failure details to build a human-readable reason: + +```yaml +name: custom/my-appsec-config +on_load: + - apply: + - LoadAPISchemaWithName("users_api", "users-api.yaml") +inband: + pre_eval: + - filter: req.URL.Path startsWith "/users" && !ValidateRequestWithSchema("users_api") + apply: + - | + DropRequest("schema validation failed: " + hook_vars.validation_error_message) +``` + +You can also use the result to pick a softer remediation, send a custom event, etc. + +### Validation result variables + +When `ValidateRequestWithSchema` returns `false`, the following keys are set on `hook_vars`. They are available to the `apply` block of the same hook, to later hooks in the same request, and to `on_match` / `post_eval` hooks. The same keys are also propagated to the resulting CrowdSec event. + +| `hook_vars` key | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `validation_error` | Full human-readable error string (combination of reason, field and message). | +| `validation_error_reason` | Failure category — `parameter`, `request_body`, `security`, `route_not_found`, `method_not_allowed`, `internal`. | +| `validation_error_field` | Name of the offending field (e.g. query parameter, header, body property) when applicable. | +| `validation_error_message` | The underlying error message from the validator. | +| `validation_error_value` | The offending value, truncated to 100 characters. | +| `validation_error_expected` | Short description of what the schema expected (e.g. `type: integer, min: 18`). | + +On success these keys are absent. + +## Authentication + +If your OpenAPI schema declares a `security` requirement on an operation, the validator enforces it as part of validation. Failure to satisfy the security requirement is reported as a `security` reason in `hook_vars`. + +| Security scheme | Supported | Notes | +| ------------------------- | --------- | ---------------------------------------------------------------------------------------------- | +| `http` `basic` | Yes | Checks that an `Authorization: Basic …` header is present and non-empty. | +| `http` `bearer` | Yes | Checks that an `Authorization: Bearer …` header is present and non-empty. | +| `apiKey` (`header`) | Yes | Checks that the named header is present and non-empty. | +| `apiKey` (`query`) | Yes | Checks that the named query parameter is present and non-empty. | +| `apiKey` (`cookie`) | Yes | Checks that the named cookie is present and non-empty. | +| `oauth2`, `openIdConnect` | No | A warning is logged at schema load. Any request guarded by such a scheme will fail validation. | + +The validator only verifies that the credential **is present and well-formed** — it does not verify the credential against any backing store. + +## End-to-end example + +`/var/lib/crowdsec/data/schemas/users-api.yaml`: + +```yaml +openapi: 3.0.0 +info: + title: Users API + version: "1.0.0" +paths: + /users: + post: + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [username, email] + additionalProperties: false + properties: + username: + type: string + minLength: 3 + maxLength: 20 + email: + type: string + format: email + responses: + "201": + description: created +``` + +AppSec configuration: + +```yaml +name: custom/my-appsec-config +on_load: + - apply: + - LoadAPISchemaWithName("users_api", "users-api.yaml") +inband: + pre_eval: + - filter: req.URL.Path startsWith "/users" && !ValidateRequestWithSchema("users_api") + apply: + - | + DropRequest("API schema violation on '" + hook_vars.validation_error_field + "': " + hook_vars.validation_error_message) +``` + +With this configuration: + +- `POST /users` with `{"username": "ab", "email": "x"}` is dropped (`username` too short, `email` malformed). +- `POST /users` with a valid body passes validation and is then evaluated by the WAF rules as usual. +- `GET /users` is dropped with reason `method_not_allowed` (default policy). +- `POST /admin` is dropped with reason `route_not_found` (default policy). + +## Metrics + +Two Prometheus counters are exposed: + +| Metric | Labels | Description | +| ----------------------------------- | ------------------------------------------------- | -------------------------------------------------------------- | +| `cs_appsec_validation_ok_total` | `source`, `appsec_engine`, `schema_ref` | Requests that passed schema validation. | +| `cs_appsec_validation_failed_total` | `source`, `appsec_engine`, `schema_ref`, `reason` | Requests that failed schema validation, broken down by reason. | + +`reason` values match `validation_error_reason`: `parameter`, `request_body`, `security`, `route_not_found`, `method_not_allowed`, `internal`. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/configuration.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/configuration.md index d26837fd3..2a62d46a2 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/configuration.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/configuration.md @@ -168,6 +168,10 @@ inband_options: request_body_in_memory_limit: 1048576 ``` +:::note +`request_body_in_memory_limit` is a Coraza-level setting. It is distinct from the engine's overall maximum body size, which bounds how much of the body CrowdSec buffers before any rule runs (defaults to 10MB). See [Request body size handling](hooks.md#request-body-size-handling) to tune it. +::: + ### outofband_options > object diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/hooks.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/hooks.md index 7fb48b38f..32f58eb72 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/hooks.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/hooks.md @@ -43,17 +43,22 @@ This hook is intended to be used to disable rules at loading (eg, to temporarily #### Available helpers -| Helper Name | Type | Description | -| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- | -| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | -| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | -| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | -| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | -| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | -| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | -| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | +| Helper Name | Type | Description | +| ------------------------------ | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | +| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | +| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | +| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | +| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | +| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | +| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | +| `LoadAPISchemaWithName` | `func(ref str, filename str)` | Load an OpenAPI schema from `/schemas/` and register it under `ref`. See [OpenAPI Schema Validation](api_validation.md). | +| `LoadAPISchemaWithOptions` | `func(ref str, filename str, opts map)` | Same as `LoadAPISchemaWithName` but accepts per-schema policy overrides (`on_route_not_found`, `on_method_not_allowed`). | +| `RegisterAPISchemaBodyDecoder` | `func(content_type str, decoder str)` | Enable a non-default body decoder for a Content-Type. See [available decoders](api_validation.md#body-decoders). | +| `SetMaxBodySize` | `func(size int)` | Set the maximum request body size (in bytes) buffered and inspected by the engine. Defaults to 10MB. See [Request body size handling](#request-body-size-handling) | +| `SetBodySizeExceededAction` | `func(action str)` | Set what happens when a request body exceeds the maximum size: `drop` (default), `partial`, or `allow`. See [Request body size handling](#request-body-size-handling) | ##### Example @@ -75,21 +80,24 @@ This hook is intended to be used to disable rules only for this particular reque #### Available helpers -| Helper Name | Type | Description | -| ------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------- | -| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | -| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | -| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | -| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | -| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | -| `IsInBand` | `bool` | `true` if the request is in the in-band processing phase | -| `IsOutBand` | `bool` | `true` if the request is in the out-of-band processing phase | -| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | -| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | -| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | -| `req` | `http.Request` | Original HTTP request received by the remediation component | -| `DropRequest` | `func(reason str)` | Stop processing the request immediately and instruct the remediation component to block the request | +| Helper Name | Type | Description | +| --------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `RemoveInBandRuleByName` | `func(tag str)` | Disable the named in-band rule | +| `RemoveInBandRuleByTag` | `func(tag str)` | Disable the in-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveInBandRuleByID` | `func(id int)` | Disable the in-band rule identified by the ID | +| `RemoveOutBandRuleByName` | `func(tag str)` | Disable the named out-of-band rule | +| `RemoveOutBandRuleByTag` | `func(tag str)` | Disable the out-of-band rule identified by the tag (multiple rules can have the same tag) | +| `RemoveOutBandRuleByID` | `func(id int)` | Disable the out-of-band rule identified by the ID | +| `IsInBand` | `bool` | `true` if the request is in the in-band processing phase | +| `IsOutBand` | `bool` | `true` if the request is in the out-of-band processing phase | +| `SetRemediationByTag` | `func(tag str, remediation string)` | Change the remediation of the in-band rule identified by the tag (multiple rules can have the same tag) | +| `SetRemediationByID` | `func(id int, remediation string)` | Change the remediation of the in-band rule identified by the ID | +| `SetRemediationByName` | `func(name str, remediation string)` | Change the remediation of the in-band rule identified by the name | +| `req` | `http.Request` | Original HTTP request received by the remediation component | +| `DropRequest` | `func(reason str)` | Stop processing the request immediately and instruct the remediation component to block the request | +| `DisableBodyInspection` | `func()` | Skip body inspection for the current request (also bypasses the maximum body size check). See [Request body size handling](#request-body-size-handling) | +| `ValidateRequestWithSchema` | `func(ref str) bool` | Validate the current request against an OpenAPI schema previously loaded under `ref` (returns `true` on success). On failure, structured details are published to `hook_vars` (see [OpenAPI Schema Validation](api_validation.md#validation-result-variables)). | +| `hook_vars` | `map[string]string` | Per-request scratch space shared with later hooks and propagated to the resulting event. Helpers such as `ValidateRequestWithSchema` publish their results here. | #### Example @@ -211,6 +219,48 @@ on_match: When using `SetRemediation*` helpers, the only special value is `allow`: the remediation component won't block the request. Any other values (including `ban` and `captcha`) are transmitted as-is to the remediation component. +### Request body size handling + +Before the request body is handed over to the rules engine, the Application Security Component reads it into memory itself. To protect the engine from oversized requests, the body is bounded by a maximum size (defaults to **10MB**). + +This limit is independent from the Coraza-level [`request_body_in_memory_limit`](configuration.md#inband_options) option: it controls how much of the body CrowdSec buffers in the first place, before any rule is evaluated. + +You can tune this behavior from an `on_load` hook: + +- `SetMaxBodySize(size)` sets the maximum body size, in bytes. The value must be a positive integer. +- `SetBodySizeExceededAction(action)` controls what happens when a body exceeds the maximum size: + + | Action | Behavior | + | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | + | `drop` (default) | The request is blocked using the default remediation, without inspecting the body. | + | `partial` | The body is truncated to the maximum size and the kept portion is inspected. Content beyond the truncation point is discarded and will not match any rule. | + | `allow` | The body is not inspected and the request is allowed to proceed (other zones are still evaluated). | + +```yaml +name: crowdsecurity/my-appsec-config +default_remediation: ban +inband_rules: + - crowdsecurity/base-config +on_load: + - apply: + - SetMaxBodySize(20971520) # 20MB + - SetBodySizeExceededAction("partial") +``` + +#### `DisableBodyInspection` + +`DisableBodyInspection()` can be called from a `pre_eval` hook to skip body inspection for the current request only. When body inspection is disabled: + +- the request body is not read or processed, so body-based zones (`BODY_ARGS`, `RAW_BODY`, …) won't match; +- the maximum body size check is bypassed as well: a request that would otherwise be dropped for exceeding the limit is allowed through, because the operator has explicitly accepted that this body won't be processed. + +```yaml +pre_eval: + - filter: req.URL.Path startsWith "/upload" + apply: + - DisableBodyInspection() +``` + ### `req` object The `pre_eval`, `on_match` and `post_eval` hooks have access to a `req` variable that represents the HTTP request that was forwarded to the appsec. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/intro.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/intro.md index ad9a06a08..285aaa740 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/intro.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/intro.md @@ -81,6 +81,11 @@ The AppSec Component works seamlessly with modern web servers and reverse proxie Quick Start Guide → +
+Envoy Gateway +Quick Start Guide → +
+
HAProxy HAProxy @@ -134,6 +139,7 @@ This lets scenarios leverage WAF rule events, such as extending a ban for an IP You can follow our quick start guides depending on your web server: - [Nginx/OpenResty](quickstart/nginxopenresty) +- [Envoy Gateway](quickstart/envoy-gateway) - [Traefik](quickstart/traefik) - [HAProxy (SPOA)](quickstart/haproxy_spoa) - [WordPress](quickstart/wordpress) diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/envoy-gateway.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/envoy-gateway.mdx new file mode 100644 index 000000000..f085b3476 --- /dev/null +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/envoy-gateway.mdx @@ -0,0 +1,499 @@ +--- +id: envoy-gateway +title: QuickStart - Envoy Gateway (Kubernetes) +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# CrowdSec WAF QuickStart for Envoy Gateway + +## Objectives + +This quickstart shows how to deploy the CrowdSec AppSec Component in Kubernetes +and protect workloads exposed through [Envoy Gateway](https://gateway.envoyproxy.io/) +using an external authorization service. + +At the end, you will have: + +- CrowdSec running in-cluster with the AppSec API listening on `7422` +- A CrowdSec-compatible Envoy external auth service running in the cluster. + This is the service Envoy calls during external authorization checks; it + queries CrowdSec LAPI and AppSec, then tells Envoy whether the request should + be allowed or denied. +- `SecurityPolicy` resources attached to your `HTTPRoute` objects. + In Envoy Gateway, a `SecurityPolicy` is the custom resource that enables + external authorization for a `Gateway` or `HTTPRoute` and points Envoy to the + auth backend. +- `HTTPRoute` objects exposing your applications. In Gateway API, an + `HTTPRoute` defines how HTTP requests for specific hostnames or paths are + matched and forwarded to your backend `Service`. +- Virtual patching and generic AppSec rules inspecting requests before they + reach your backends + +## Prerequisites + +1. If you're new to the [AppSec Component](/appsec/intro.md#introduction) or + **W**eb **A**pplication **F**irewalls, start with the + [Introduction](/appsec/intro.md#introduction). + +2. It is assumed that you already have: + - A working **CrowdSec [Security Engine](/intro.mdx)** installation. For a + Kubernetes install quickstart, refer to + [/u/getting_started/installation/kubernetes](/u/getting_started/installation/kubernetes). + - A working **Envoy Gateway** installation with the Gateway API CRDs and an + accepted `GatewayClass`. + - Existing `Gateway` / `HTTPRoute` resources exposing your applications. + +:::important +For remediation to work correctly, CrowdSec must see the real client IP in the +Envoy access logs, and the bouncer must evaluate requests against that same IP. + +If Envoy only logs an internal proxy, load balancer, or node IP, CrowdSec will +create decisions for the wrong source and bouncing will not work as expected. + +In Kubernetes, make sure the Envoy service configuration preserves source IPs, +for example by setting `externalTrafficPolicy: Local` instead of a setup that +hides the original client IP. +::: + +:::warning +This integration currently relies on a community Envoy external auth bouncer, +not on a first-party CrowdSec remediation component. + +The upstream project used in this guide is: + +- `kdwils/envoy-proxy-crowdsec-bouncer` + ::: + +## Store the Envoy bouncer key in a Kubernetes secret + +For Envoy Gateway, a practical approach is to choose a fixed key, store it in a +Kubernetes secret, and force `BOUNCER_KEY_envoy` from `lapi.env` with +`valueFrom.secretKeyRef`. + +Create or update the secret used by CrowdSec LAPI: + +```yaml title="crowdsec-keys.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-keys + namespace: crowdsec +type: Opaque +stringData: + ENROLL_KEY: "" + BOUNCER_KEY_envoy: "" +``` + +Apply it: + +```bash +kubectl apply -f crowdsec-keys.yaml +``` + +Then reference `BOUNCER_KEY_envoy` from the CrowdSec Helm values: + +```yaml title="crowdsec-values.yaml" +lapi: + env: + - name: BOUNCER_KEY_envoy + valueFrom: + secretKeyRef: + name: crowdsec-keys + key: BOUNCER_KEY_envoy +``` + +Apply the CrowdSec release again: + +```bash +helm upgrade --install crowdsec crowdsec/crowdsec \ + --namespace crowdsec \ + --create-namespace \ + -f crowdsec-values.yaml +``` + +## Deploy CrowdSec with AppSec enabled + +Add this to the CrowdSec `values.yaml` to enable the AppSec acquisition +datasource and load the default AppSec configuration: + +```yaml title="crowdsec-values.yaml" +agent: + acquisition: + - namespace: envoy-gateway-system + podName: envoy-default-* + poll_without_inotify: true + program: envoy + env: + - name: COLLECTIONS + value: yanis-kouidri/envoy + - name: DEBUG + value: "true" +appsec: + acquisitions: + - appsec_configs: + - crowdsecurity/appsec-default + labels: + type: appsec + listen_addr: 0.0.0.0:7422 + path: / + source: appsec + enabled: true + env: + - name: COLLECTIONS + value: crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules +lapi: + env: + - name: BOUNCER_KEY_envoy + valueFrom: + secretKeyRef: + key: BOUNCER_KEY_envoy + name: crowdsec-keys +``` + +Apply or upgrade the CrowdSec release: + +```bash +helm upgrade --install crowdsec crowdsec/crowdsec \ + --namespace crowdsec \ + --create-namespace \ + -f crowdsec-values.yaml +``` + +Verify the CrowdSec pods: + +```bash +kubectl -n crowdsec get pods +kubectl -n crowdsec get svc crowdsec-service crowdsec-appsec-service +``` + +You should see: + +- `crowdsec-lapi` in `Running` +- `crowdsec-appsec` in `Running` +- `crowdsec-service` exposing port `8080` +- `crowdsec-appsec-service` exposing port `7422` + +## Deploy the Envoy external auth bouncer + + + + +For the Helm-based install, keep the API key in a Kubernetes `Secret` and +reference that secret from a user-managed `values.yaml` file. + +Create the secret holding the CrowdSec bouncer key: + +```yaml title="crowdsec-envoy-bouncer-secret.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-envoy-bouncer-secrets + namespace: envoy-gateway-system +type: Opaque +stringData: + api-key: "" +``` + +Apply it: + +```bash +kubectl apply -f crowdsec-envoy-bouncer-secret.yaml +``` + +Then create a values file: + +```yaml title="envoy-bouncer-values.yaml" +fullnameOverride: crowdsec-envoy-bouncer +config: + bouncer: + lapiURL: http://crowdsec-service.crowdsec.svc.cluster.local:8080 + apiKeySecretRef: + name: crowdsec-envoy-bouncer-secrets + key: api-key + waf: + enabled: true + appSecURL: http://crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 + apiKeySecretRef: + name: crowdsec-envoy-bouncer-secrets + key: api-key +securityPolicy: + create: true + gatewayName: shared-public + gatewayNamespace: envoy-gateway-system +``` + +Install the chart: + +```bash +helm install crowdsec-envoy-bouncer oci://ghcr.io/kdwils/charts/envoy-proxy-bouncer \ + --namespace envoy-gateway-system \ + --create-namespace \ + -f envoy-bouncer-values.yaml +``` + +If you only want to deploy the bouncer and manage `SecurityPolicy` objects +manually, omit the `securityPolicy.*` settings. + + + + +Keep the bouncer API key in a Kubernetes secret in the namespace where your +Envoy Gateway infrastructure runs. In this example, that namespace is +`envoy-gateway-system`. + +```yaml title="crowdsec-envoy-bouncer-secret.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-envoy-bouncer-secrets + namespace: envoy-gateway-system +type: Opaque +stringData: + api-key: "" +``` + +Apply the secret: + +```bash +kubectl apply -f crowdsec-envoy-bouncer-secret.yaml +``` + +Then create the bouncer objects directly: + +```yaml title="crowdsec-envoy-bouncer.yaml" +apiVersion: apps/v1 +kind: Deployment +metadata: + name: crowdsec-envoy-bouncer + namespace: envoy-gateway-system +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: crowdsec-envoy-bouncer + template: + metadata: + labels: + app.kubernetes.io/name: crowdsec-envoy-bouncer + spec: + containers: + - name: crowdsec-envoy-bouncer + image: ghcr.io/kdwils/envoy-proxy-bouncer:v0.6.0 + imagePullPolicy: Always + ports: + - name: grpc + containerPort: 8080 + protocol: TCP + env: + - name: ENVOY_BOUNCER_BOUNCER_ENABLED + value: "true" + - name: ENVOY_BOUNCER_BOUNCER_APIKEY + valueFrom: + secretKeyRef: + name: crowdsec-envoy-bouncer-secrets + key: api-key + - name: ENVOY_BOUNCER_BOUNCER_LAPIURL + value: http://crowdsec-service.crowdsec.svc.cluster.local:8080 + - name: ENVOY_BOUNCER_WAF_ENABLED + value: "true" + - name: ENVOY_BOUNCER_WAF_APIKEY + valueFrom: + secretKeyRef: + name: crowdsec-envoy-bouncer-secrets + key: api-key + - name: ENVOY_BOUNCER_WAF_APPSECURL + value: http://crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 + - name: ENVOY_BOUNCER_SERVER_GRPCPORT + value: "8080" + - name: ENVOY_BOUNCER_SERVER_HTTPPORT + value: "8081" + - name: ENVOY_BOUNCER_SERVER_LOGLEVEL + value: info +--- +apiVersion: v1 +kind: Service +metadata: + name: crowdsec-envoy-bouncer + namespace: envoy-gateway-system +spec: + selector: + app.kubernetes.io/name: crowdsec-envoy-bouncer + ports: + - name: grpc + port: 8080 + targetPort: grpc + protocol: TCP +``` + +Apply it: + +```bash +kubectl apply -f crowdsec-envoy-bouncer.yaml +``` + +This path gives you full control over the generated objects, but you must keep +the `Deployment`, `Service`, and `ReferenceGrant` aligned yourself. + + + + +Verify the rollout: + +```bash +kubectl -n envoy-gateway-system rollout status deploy/crowdsec-envoy-bouncer +``` + +## Attach Envoy `SecurityPolicy` resources to `HTTPRoute`s + +Envoy Gateway external auth is configured through +`gateway.envoyproxy.io/v1alpha1` `SecurityPolicy` resources. + +:::note +Attaching the `SecurityPolicy` to an `HTTPRoute` is usually better than +attaching it to the `Gateway`. + +It keeps the policy scoped to one application route instead of every route on +the shared entrypoint, which makes rollout, debugging, and multi-application +setups easier to manage. +::: + +Attach them at the `HTTPRoute` level: + +```yaml title="app-securitypolicy.yaml" +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: crowdsec-ext-auth + namespace: "" +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: "" + extAuth: + failOpen: true + grpc: + backendRefs: + - group: "" + kind: Service + name: crowdsec-envoy-bouncer + namespace: envoy-gateway-system + port: 8080 +``` + +Apply them: + +```bash +kubectl apply -f app-securitypolicy.yaml +``` + +## Allow cross-namespace references + +The Helm chart can create the required `ReferenceGrant` for you. In the example +above, this is handled by: + +```yaml +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: ReferenceGrant +metadata: + name: crowdsec-ext-auth-backend + namespace: envoy-gateway-system +spec: + from: + - group: gateway.envoyproxy.io + kind: SecurityPolicy + namespace: default + to: + - group: "" + kind: Service + name: crowdsec-envoy-bouncer +``` + +If you do not let the chart manage `ReferenceGrant`, you must create an +equivalent `ReferenceGrant` manually in `envoy-gateway-system`. + +## Testing detection + +### Test the HTTP generic scenario + +You can verify that CrowdSec is parsing Envoy logs correctly by triggering the +`crowdsecurity/http-generic-test` dummy scenario. + +1. Access your service URL with this path: + `/crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl` + +```bash +curl -I http:///crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl +``` + +2. Confirm the alert has triggered for `crowdsecurity/http-generic-test`: + +```bash +kubectl exec -n crowdsec -it $(kubectl get pods -n crowdsec -l k8s-app=crowdsec -l type=lapi -o name) -- cscli alerts list -s crowdsecurity/http-generic-test +``` + +:::warning +If you trigger this scenario from a private ip, you won't see it trigger as it will be dismissed by the whitelist parser. +::: + +### Test the AppSec generic scenario + +If AppSec forwarding is enabled, the same probe path also lets you verify the +`crowdsecurity/appsec-generic-test` dummy scenario. + +1. Access your service URL with this path: + `/crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl` + +```bash +curl -I http:///crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl +``` + +2. Confirm the alert has triggered for `crowdsecurity/appsec-generic-test`: + +```bash +kubectl exec -n crowdsec -it $(kubectl get pods -n crowdsec -l k8s-app=crowdsec -l type=lapi -o name) -- cscli alerts list -s crowdsecurity/appsec-generic-test +``` + +:::warning +If you trigger this scenario from a private ip, you won't see it trigger as it will be dismissed by the whitelist parser. +::: + +## Important Notes + +### Attach `SecurityPolicy` to `HTTPRoute`s, not just to the `Gateway` + +For Envoy Gateway, route-level attachment is the safer pattern for this +integration. Attaching the policy at the `Gateway` level can apply external +auth to every routed application behind that listener, which increases the +blast radius of a bad policy, a broken backend reference, or an unhealthy +bouncer. Attaching it to individual `HTTPRoute`s keeps the rollout explicit and +incremental: you can protect only the routes that should use CrowdSec, leave +other traffic untouched, and troubleshoot one application at a time. + +### Cross-namespace bouncer references still require `ReferenceGrant` + +If your bouncer `Service` is in `envoy-gateway-system` and your applications +live in other namespaces, `ReferenceGrant` is required. The ReferenceGrant has +to correctly specify the crowdsec bouncer service. + +### Use `failOpen: true` during rollout + +If you apply a fail-closed external auth policy before the bouncer is healthy, +Envoy will start rejecting traffic with `403` + +### Check image architecture support + +The community bouncer image is published for amd64. For other architectures you +will need a custom build. + +## Next steps + +You are now running the AppSec Component on your CrowdSec Security Engine. + +As the next steps, you can: + +- Monitor WAF alerts in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/general.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/general.mdx index ff7f2eaa6..bba37fee4 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/general.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/general.mdx @@ -135,7 +135,7 @@ INFO[...] Appsec Runner ready to process event ``` -## Next Steps +## Next steps Now that the AppSec Component is configured and running, you need to: @@ -145,11 +145,16 @@ Now that the AppSec Component is configured and running, you need to: For specific remediation component configuration, see: - [Nginx/OpenResty Setup](nginxopenresty.mdx) +- [OpenResty Setup](nginxopenresty.mdx) - [Traefik Setup](traefik.mdx) - [HAProxy (SPOA) Setup](haproxy_spoa.mdx) - [WordPress Setup](wordpress.mdx) - [Check the hub for other remediation components supporting AppSec](https://app.crowdsec.net/hub/remediation-components) +Once your remediation component is in place, continue with: +- Reviewing the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Exploring [WAF deployment strategies](/appsec/advanced_deployments.mdx) when you are ready to expand beyond the initial setup. + ### Testing Detection If you've enabled an WAF-capable bouncer with CrowdSec WAF, you can trigger the `crowdsecurity/appsec-generic-test` dummy scenario. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/haproxy_spoa.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/haproxy_spoa.mdx index e43a8b06f..ac453a309 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/haproxy_spoa.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/haproxy_spoa.mdx @@ -3,77 +3,52 @@ id: haproxy_spoa title: QuickStart - HAProxy (SPOA) --- -import UnderlineTooltip from '@site/src/components/underline-tooltip'; - # CrowdSec WAF QuickStart for HAProxy (SPOA) -## Objectives - -Set up the [AppSec Component](/appsec/intro.md#introduction) to protect web applications running behind [HAProxy](https://www.haproxy.org/) using the **HAProxy SPOA remediation component**. - -You will: -- Enable CrowdSec AppSec (WAF) in the Security Engine. -- Install and configure `crowdsec-haproxy-spoa-bouncer` so HAProxy can forward HTTP requests to AppSec. -- Validate everything by triggering a test detection. +Protect web applications running behind [HAProxy](https://www.haproxy.org/) with CrowdSec's [AppSec (WAF) Component](/appsec/intro.md#introduction), using the HAProxy SPOA remediation component to forward HTTP requests. ## Prerequisites -1. If you're new to the [AppSec Component](/appsec/intro.md#introduction) or **W**eb **A**pplication **F**irewalls, start with the [Introduction](/appsec/intro.md#introduction). -2. It's assumed that you have already installed: - - **CrowdSec [Security Engine](/intro.mdx)**: for installation, refer to the [QuickStart guide](/u/getting_started/installation/linux). - - **HAProxy**: already running and proxying your application(s). - - **HAProxy SPOA [Remediation Component](/u/bouncers/intro)**: `crowdsec-haproxy-spoa-bouncer`. - -:::tip Already did the base setup? -If you already completed the [General Setup](general.mdx) (collections + acquisition), skip to [Remediation Component Setup](#remediation-component-setup). -::: - -## AppSec Component Setup +Make sure the following are already done on the machine running HAProxy (each is a single-page install guide): -### Collection installation +1. **CrowdSec Security Engine** installed and running — see the [Linux quickstart](/u/getting_started/installation/linux). +2. **HAProxy** already running and proxying your application(s). +3. **HAProxy SPOA bouncer** (`crowdsec-haproxy-spoa-bouncer`) installed and registered against the CrowdSec LAPI. See the [SPOA bouncer guide](/u/bouncers/haproxy_spoa). -Install the main AppSec rule collections: +## 1. Install the AppSec rule collections ```bash -sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules +sudo cscli collections install \ + crowdsecurity/appsec-virtual-patching \ + crowdsecurity/appsec-generic-rules ``` -These collections provide virtual patching (CVE rules), generic WAF detections, and the default AppSec configuration. +This pulls the [`appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection (rules for known CVEs, auto-updated daily) and the [`appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection (common attack patterns), plus the default AppSec configuration. -### Setup the acquisition +## 2. Turn on the AppSec Component -Create `/etc/crowdsec/acquis.d/appsec.yaml` (see the [AppSec datasource](/log_processor/data_sources/appsec.md) for the full reference): +Create the acquisition file, then restart CrowdSec: -```yaml title="/etc/crowdsec/acquis.d/appsec.yaml" +```bash +sudo mkdir -p /etc/crowdsec/acquis.d +sudo tee /etc/crowdsec/acquis.d/appsec.yaml > /dev/null <<'EOF' appsec_configs: - crowdsecurity/appsec-default labels: type: appsec listen_addr: 127.0.0.1:7422 source: appsec -``` - -Restart CrowdSec: - -```bash +EOF sudo systemctl restart crowdsec ``` :::warning -Do not expose the AppSec Component to the internet. It should only be reachable from your reverse proxy. +Keep `listen_addr` on `127.0.0.1` — the AppSec Component must only be reachable from your reverse proxy. ::: -## Remediation Component Setup - -### Install and configure the HAProxy SPOA bouncer +## 3. Enable AppSec forwarding in the SPOA bouncer -Read here how to install the SPOA remediation component: [HAProxy SPOA remediation component docs](/u/bouncers/haproxy_spoa). - -Once the bouncer is installed and able to talk to CrowdSec LAPI, you only need to enable **AppSec forwarding**. - -### Enable AppSec forwarding in the bouncer (YAML) - -In `/etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml`, configure the AppSec endpoint the bouncer should query for WAF evaluation: +Edit `/etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml` and add the `appsec_url` plus the `appsec` block under your host(s): ```yaml title="/etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml" # AppSec (WAF forwarding) @@ -96,55 +71,51 @@ sudo systemctl restart crowdsec-spoa-bouncer If AppSec runs on a different host (or in containers), update `appsec_url` to the correct reachable address. ::: -:::warning AppSec limitations with HAProxy SPOA (important) -HAProxy SPOA forwarding is constrained by HAProxy/SPOE/SPOA mechanics: -- Request bodies are only available if you enable buffering (`option http-buffer-request`) and they must fit within tight size limits (commonly capped at ~50KB in examples). -- When the body is too large (uploads, large JSON, etc.), you typically fall back to a “no-body” SPOE group, which means **body-dependent WAF rules cannot match**. -- You are not doing full “streaming” inspection: SPOA works with what HAProxy can capture and send to the agent within buffer/frame limits. - -CrowdSec AppSec is still a single “source of truth” for rules/config: you can point multiple WAF-capable integrations to the same AppSec endpoint so rule updates stay in sync across your infrastructure. - -Recommended layered approach: -- Use HAProxy SPOA for **edge enforcement** (IP/range/country decisions, ban/captcha) and lightweight WAF evaluation when the request fits within the configured limits. -- Put a full-featured L7 proxy/WAF-capable integration **downstream** (or protect the app directly) when you need deeper inspection of large bodies, file uploads, or application-specific request parsing. Examples of WAF-capable integrations include: - - [Nginx/OpenResty](/appsec/quickstart/nginxopenresty) - - [Traefik](/appsec/quickstart/traefik) - - [WordPress](/appsec/quickstart/wordpress) -::: - -## Testing the AppSec Component + Remediation Component - -:::note -Adjust the URL below to match your HAProxy frontend (HTTP/HTTPS, port, hostname). -::: +## 4. Verify -If you try to access `http(s):///.env`, your request should be blocked: +Hit an endpoint that should trip an AppSec rule (adjust the URL to match your HAProxy frontend): ```bash -curl -i http:///.env +curl -I http:///.env ``` -![appsec-denied](/img/appsec_denied.png) +You should get an `HTTP/1.1 403 Forbidden` response. -You can also check AppSec metrics: +Check that CrowdSec recorded the block: ```bash sudo cscli metrics show appsec ``` -### Explanation +
+What just happened? + +1. `curl` hit HAProxy at `/.env`. +2. HAProxy forwarded the request to the SPOA remediation component. +3. The bouncer queried the AppSec Component at `appsec_url`. +4. The request matched the [`vpatch-env-access`](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) rule. +5. AppSec answered `403`; HAProxy blocked the request. + +
+ +## AppSec limitations with HAProxy SPOA -What happened in the test above is: +HAProxy SPOA forwarding is constrained by HAProxy/SPOE/SPOA mechanics: +- Request bodies are only available if you enable buffering (`option http-buffer-request`) and must fit within tight size limits (commonly capped at ~50 KB). +- When the body is too large (uploads, large JSON, etc.), you typically fall back to a "no-body" SPOE group, which means **body-dependent WAF rules cannot match**. +- This is not full streaming inspection: SPOA works with what HAProxy can capture within buffer/frame limits. + +CrowdSec AppSec is a single source of truth for rules — you can point multiple WAF-capable integrations at the same AppSec endpoint so rule updates stay in sync. -1. You requested `/.env` through HAProxy. -2. HAProxy forwarded the request to the SPOA remediation component (SPOE/SPOA). -3. The remediation component queried the AppSec Component at `appsec_url`. -4. The request matched the [AppSec rule to detect `.env` access](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access). -5. AppSec returned a blocking action (HTTP 403) to the remediation component. -6. HAProxy blocked the request. +Recommended layered approach: +- Use HAProxy SPOA for **edge enforcement** (IP/range/country decisions, ban/captcha) and lightweight WAF evaluation when the request fits within the configured limits. +- Put a full-featured L7 proxy/WAF-capable integration **downstream** (or protect the app directly) when you need deeper inspection of large bodies, file uploads, or application-specific request parsing. Examples: + - [Nginx/OpenResty](nginxopenresty.mdx) + - [Traefik](traefik.mdx) + - [WordPress](wordpress.mdx) ## Next steps -- Monitor WAF alerts with `sudo cscli alerts list` and in the [CrowdSec Console](https://app.crowdsec.net). -- Tune rules and configurations: `/appsec/configuration.md` and `/appsec/configuration_rule_management.md`. -- Troubleshoot: `/appsec/troubleshooting.md` and [HAProxy SPOA remediation component docs](/u/bouncers/haproxy_spoa). +- Monitor WAF alerts with `sudo cscli alerts list` or in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) and the [HAProxy SPOA bouncer docs](/u/bouncers/haproxy_spoa) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx) if you want to expand beyond this initial setup. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginx-ingress.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginx-ingress.mdx index dedefeac7..edb3bd28c 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginx-ingress.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginx-ingress.mdx @@ -340,6 +340,6 @@ Once done, all your alerts, including the ones generated by the AppSec Component You are now running the AppSec Component on your CrowdSec Security Engine. As the next steps, you can: - - Look at [WAF Deployment Strategies](/appsec/advanced_deployments.mdx) to discover how to gradually improve your WAF security. - - Look at the [Rules syntax](/appsec/rules_syntax.md) and [creation process](/appsec/create_rules.md) to create your own and contribute - - Take a look at [the benchmarks](/appsec/benchmark.md) +- Monitor WAF alerts in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginxopenresty.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginxopenresty.mdx index d57efa85a..a3a41d260 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginxopenresty.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/nginxopenresty.mdx @@ -3,257 +3,102 @@ id: nginxopenresty title: QuickStart - Nginx / OpenResty --- - import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -import CodeBlock from '@theme/CodeBlock'; -import UnderlineTooltip from '@site/src/components/underline-tooltip'; - -# CrowdSec WAF QuickStart for Nginx/OpenResty - -## Objectives - -The goal of this quickstart is to set up the [AppSec Component](/appsec/intro.md#introduction) to safeguard web applications running on [Nginx](https://nginx.com) or [OpenResty](https://openresty.org/en/). -We'll deploy a [set of rules](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) designed to block [well-known attacks](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) and [currently exploited vulnerabilities](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). +# CrowdSec WAF QuickStart for Nginx / OpenResty -Additionally, we'll show how to monitor these alerts through the [Console](https://app.crowdsec.net/). +Protect an [Nginx](https://nginx.com) or [OpenResty](https://openresty.org/en/) server with CrowdSec's [AppSec (WAF) Component](/appsec/intro.md#introduction). After the prerequisites below, every step is a single copy-paste command. Most steps are the same for both engines — only step 3 differs, and the tabs there let you pick the right variant. ## Prerequisites -1. If you're new to the [AppSec Component](/appsec/intro.md#introduction) or **W**eb **A**pplication **F**irewalls, start with the [Introduction](/appsec/intro.md#introduction) for a better understanding. - -2. It's assumed that you have already installed: - - **CrowdSec [Security Engine](/intro.mdx)**: for installation, refer to the [QuickStart guide](/u/getting_started/installation/linux). The AppSec Component, which analyzes HTTP requests, is included within the security engine as a [Acquisition](/log_processor/data_sources/appsec.md). - - One of the supported web servers for this guide: - - Nginx **[Remediation Component](/u/bouncers/intro)**: installation instructions are available in the [QuickStart guide](/u/bouncers/nginx). - - OpenResty **[Remediation Component](/u/bouncers/intro)**: installation instructions are available in the [QuickStart guide](/u/bouncers/openresty). - - This component intercepts HTTP requests at the webserver or reverse-proxy level and forwards them to the AppSec Component for analysis and action. - -:::info -The reason we provide Nginx and OpenResty in a single guide is that OpenResty is a web server based on Nginx just the configuration paths are different -::: - -:::tip Already did the base setup? -If you already completed the [General Setup](general.mdx) (collections + acquisition), skip to [Remediation Component Setup](#remediation-component-setup). -::: - -## AppSec Component Setup - -### Collection installation - -To begin setting up the AppSec Component, the initial step is to install a relevant set of rules. - -We will utilize the [`crowdsecurity/appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection, which offers a wide range of rules aimed at identifying and preventing the exploitation of known vulnerabilities. - -This collection is regularly updated to include protection against newly discovered vulnerabilities. Upon installation, it receives automatic daily updates to ensure your protection is always current. -We also install the [`crowdsecurity/appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection. This collection contains detection scenarios for generic attack vectors. It provides protection in cases where specific scenarios for vulnerabilities do not exist yet. - -On the machine where the Security Engine is installed, just execute the following command: - -:::info -You can always view the content of a [collection on the Hub](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). -::: - -``` -sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules -``` - -Executing this command will install the following items: - -- The [*AppSec Rules*](/appsec/rules_syntax.md) contain the definition of malicious requests to be matched and stopped -- The [*AppSec Configuration*](/appsec/configuration.md#appsec-configuration-files) links together a set of rules to provide a coherent set -- The CrowdSec Parser and CrowdSec Scenario(s) bans for a longer duration repeating offenders - -### Setup the Acquisition - -Having installed the required components, it's time to configure the CrowdSec acquisition datasource for the AppSec Component ([AppSec datasource](/log_processor/data_sources/appsec.md)). This configuration allows Nginx/OpenResty to forward requests to the AppSec Component for evaluation and decision-making. +Make sure the following are already done on the machine running your web server (all are single-page install guides): -Steps: +1. **CrowdSec Security Engine** installed and running — see the [Linux quickstart](/u/getting_started/installation/linux). +2. **Nginx or OpenResty bouncer** installed and registered against the CrowdSec LAPI: + - Nginx: [`crowdsec-nginx-bouncer`](/u/bouncers/nginx#installation) + - OpenResty: [`crowdsec-openresty-bouncer`](/u/bouncers/openresty#installation) +3. Nginx or OpenResty is currently serving traffic on port 80 (used by the verification step at the end). -1. Create the acquisition directory (if it doesn't exist on your machine): - ```bash - sudo mkdir -p /etc/crowdsec/acquis.d/ - ``` - -2. Create `/etc/crowdsec/acquis.d/appsec.yaml`: - ```yaml title="/etc/crowdsec/acquis.d/appsec.yaml" - appsec_configs: - - crowdsecurity/appsec-default - labels: - type: appsec - listen_addr: 127.0.0.1:7422 - source: appsec - ``` - -The two important directives in this configuration file are: - - - `appsec_configs` is the list of [*AppSec Configurations*](/appsec/configuration.md#appsec-configuration-files) that was included in the Collection we just installed. - - the `listen_addr` is the IP and port the AppSec Component will listen to. - -:::warning -We do not recommend exposing the AppSec Component to the internet. It should only be accessible from the web server or reverse proxy. -::: - -:::info -You can find more about the [supported options for the acquisition here](/log_processor/data_sources/appsec.md) -::: - -You can now restart CrowdSec: +## 1. Install the AppSec rule collections ```bash -sudo systemctl restart crowdsec +sudo cscli collections install \ + crowdsecurity/appsec-virtual-patching \ + crowdsecurity/appsec-generic-rules ``` -#### Testing the AppSec Component - -##### Verify the AppSec Component is listening - -To verify that the AppSec Component is running correctly, we can first check that the port `7422` is open and listening: - -:::note -If you have changed the port in the configuration file, replace `7422` with the new port number. -::: - - - - - sudo netstat -tlpn | grep 7422 - - - - sudo ss -tlpn | grep 7422 - - +This pulls the [`appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection (rules for known CVEs, auto-updated daily) and the [`appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection (common attack patterns), plus the default AppSec configuration. -
+## 2. Turn on the AppSec Component -Output example +Create the acquisition file, then restart CrowdSec: ```bash -tcp 0 0 127.0.0.1:7422 0.0.0.0:* LISTEN 12345/crowdsec -``` - -:::note -The output may look different depending on the command you used. As long as you see port 7422 and the `crowdsec` process, the AppSec Component is running. -::: - -
- -##### (Optional) Manually testing the AppSec Component with `curl` - -
- Expand for short guide - -Before we proceed with configuring the Remediation Component, let's verify that all our current setups are functioning correctly. - -1. Create a Remediation Component (Bouncer) API Key: - -```bash -sudo cscli bouncers add test_waf -k this_is_a_bad_password -API key for 'test_waf': - - this_is_a_bad_password - -Please keep this key since you will not be able to retrieve it! -``` - -2. Emit a legitimate request to the AppSec Component: - -```bash -curl -X POST localhost:7422/ -i -H 'x-crowdsec-appsec-uri: /test' -H 'x-crowdsec-appsec-ip: 192.168.1.1' -H 'x-crowdsec-appsec-host: foobar.com' -H 'x-crowdsec-appsec-verb: POST' -H 'x-crowdsec-appsec-api-key: this_is_a_bad_password' -``` - -Which will give us an answer such as: - -```bash -HTTP/1.1 200 OK -Date: Tue, 30 Jan 2024 15:43:50 GMT -Content-Length: 36 -Content-Type: text/plain; charset=utf-8 - -{"action":"allow","http_status":200} +sudo mkdir -p /etc/crowdsec/acquis.d +sudo tee /etc/crowdsec/acquis.d/appsec.yaml > /dev/null <<'EOF' +appsec_configs: + - crowdsecurity/appsec-default +labels: + type: appsec +listen_addr: 127.0.0.1:7422 +source: appsec +EOF +sudo systemctl restart crowdsec ``` -3. Emit a malevolent request to the Appsec Component: - -:::info -We're trying to access a `.env` file, a [common way to retrieve credentials left by mistake](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access). +:::warning +Keep `listen_addr` on `127.0.0.1` — the AppSec Component must not be reachable from the internet. It should only be queried by your local web server / reverse proxy. ::: -```bash -curl -X POST localhost:7422/ -i -H 'x-crowdsec-appsec-uri: /.env' -H 'x-crowdsec-appsec-ip: 192.168.1.1' -H 'x-crowdsec-appsec-host: foobar.com' -H 'x-crowdsec-appsec-verb: POST' -H 'x-crowdsec-appsec-api-key: this_is_a_bad_password' - -``` +## 3. Point the bouncer at the AppSec Component -Our request is detected and blocked by the AppSec Component: + + ```bash -HTTP/1.1 403 Forbidden -Date: Tue, 30 Jan 2024 15:57:08 GMT -Content-Length: 34 -Content-Type: text/plain; charset=utf-8 - -{"action":"ban","http_status":403} +sudo sed -i 's|^APPSEC_URL=.*|APPSEC_URL=http://127.0.0.1:7422|' \ + /etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf +sudo systemctl restart nginx ``` -Let's now delete our test API Key: + + ```bash -sudo cscli bouncers delete test_waf +sudo sed -i 's|^APPSEC_URL=.*|APPSEC_URL=http://127.0.0.1:7422|' \ + /etc/crowdsec/bouncers/crowdsec-openresty-bouncer.conf +sudo systemctl restart openresty ``` -
- -## Remediation Component Setup + + -Since our AppSec Component is active and listening, we can now configure the Remediation Component to forward requests to it. +The default bouncer config already contains an empty `APPSEC_URL=` line, so `sed -i` replaces it in place — the command is idempotent and safe to re-run. -To setup forwarding of requests in the remediation component, we'll modify its configuration file and append the following line: +## 4. Verify -- `Nginx`: `/etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf` -- `OpenResty`: `/etc/crowdsec/bouncers/crowdsec-openresty-bouncer.conf` +Send a request that should trip an AppSec rule: ```bash -APPSEC_URL=http://127.0.0.1:7422 +curl -I http://localhost/.env ``` -This instructs the remediation component to communicate with the AppSec Component at `http://127.0.0.1:7422`. +You should get an `HTTP/1.1 403 Forbidden` response. -Once configured, all incoming HTTP requests will be sent there for analysis. The snippet above assumes that the AppSec Component is running on the same machine. +We're hitting a `.env` file, a [common way to retrieve credentials left by mistake](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) — the AppSec Component detects and blocks it. -We can now restart the service: +Check that CrowdSec recorded the block: ```bash -sudo systemctl restart nginx +sudo cscli metrics show appsec ``` -## Testing the AppSec Component + Remediation Component - -:::note -We're assuming the web server is installed on the same machine and is listening on port 80. Please adjust your testing accordingly if this is not the case. -You can also look at the [General WAF Testing](/docs/appsec/quickstart/general.mdx#testing-waf-component) -::: - - - -if you try to access `http://localhost/.env` from a browser, your request will be blocked, resulting in the display of the following HTML page: - -![appsec-denied](/img/appsec_denied.png) - -We can also look at the metrics from `cscli metrics show appsec` it will display: - - the number of requests processed by the AppSec Component - - Individual rule matches - -
- Example Output +
+Example metrics output ```bash title="sudo cscli metrics show appsec" Appsec Metrics: @@ -273,31 +118,28 @@ Appsec '127.0.0.1:7422/' Rules Metrics:
-### Explanation +
+What just happened? + +1. `curl` hit your web server at `/.env`. +2. The bouncer forwarded the request to the AppSec Component on `127.0.0.1:7422`. +3. The request matched the [`vpatch-env-access`](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) rule. +4. The AppSec Component answered `403`, the bouncer enforced it, and the web server returned the CrowdSec ban page. -What happened in the test that we just did is: +
- 1. We did a request (`localhost/.env`) to our local webserver - 2. Thanks to the Remediation Component configuration, forwarded the request to `http://127.0.0.1:7422` - 3. Our AppSec Component, listening on `http://127.0.0.1:7422` analyzed the request - 4. The request matches the [AppSec rule to detect .env access](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) - 5. The AppSec Component thus answered with [HTTP 403](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403) to the Remediation Component, indicating that the request must be blocked - 6. The web server then presented us with the default "request blocked" page. +If you'd rather see the block in a browser, visit `http:///.env` — you'll get the CrowdSec ban page: -## Integration with the Console +![appsec-denied](/img/appsec_denied.png) -If you haven't yet, follow the guide about [how to enroll your Security Engine in the Console](/u/getting_started/post_installation/console). +## Monitor in the Console -Once done, all your alerts, including the ones generated by the AppSec Component, appear in the Console: +If you haven't enrolled the Security Engine yet, follow [how to enroll in the Console](/u/getting_started/post_installation/console). Once enrolled, AppSec alerts show up alongside the rest of your alerts: ![appsec-console](/img/appsec_console.png) - ## Next steps -You are now running the AppSec Component on your CrowdSec Security Engine. - -As the next steps, you can: - - Look at [WAF Deployment Strategies](/appsec/advanced_deployments.mdx) to discover how to gradually improve your WAF security. - - Look at the [Rules syntax](/appsec/rules_syntax.md) and [creation process](/appsec/create_rules.md) to create your own and contribute - - Take a look at [the benchmarks](/appsec/benchmark.md) +- Monitor WAF alerts with `sudo cscli alerts list` or in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/npmplus.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/npmplus.mdx index bdadca18f..19862a9ac 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/npmplus.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/npmplus.mdx @@ -3,95 +3,42 @@ id: npmplus title: QuickStart - NPMplus --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import CodeBlock from '@theme/CodeBlock'; -import UnderlineTooltip from '@site/src/components/underline-tooltip'; - # CrowdSec WAF QuickStart for NPMplus -## Objectives - -The goal of this quickstart is to set up the [AppSec Component](/appsec/intro.md#introduction) to safeguard web applications running on [NPMplus](https://github.com/ZoeyVid/NPMplus), an enhanced version of Nginx Proxy Manager. +Protect web applications running behind [NPMplus](https://github.com/ZoeyVid/NPMplus) (an enhanced Nginx Proxy Manager fork with built-in CrowdSec support) with CrowdSec's [AppSec (WAF) Component](/appsec/intro.md#introduction). -We'll deploy a [set of rules](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) designed to block [well-known attacks](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) and [currently exploited vulnerabilities](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). - -Additionally, we'll show how to monitor these alerts through the [Console](https://app.crowdsec.net/). +This flow is mostly Docker Compose work: you download the NPMplus compose file, edit a few values, add an AppSec acquisition, start the stack, and enable AppSec from the NPMplus admin UI. ## Prerequisites -1. If you're new to the [AppSec Component](/appsec/intro.md#introduction) or **W**eb **A**pplication **F**irewalls, start with the [Introduction](/appsec/intro.md#introduction) for a better understanding. - -2. It's assumed that you have: - - **Docker and Docker Compose** installed and ready - - **Ports available**: 80/TCP, 443/TCP, 443/UDP (exposed to internet), 81/TCP (admin interface, can be internal) - - A text editor (e.g., nano, vim) and a way to download files (e.g., curl) - -:::info -NPMplus is an enhanced version of Nginx Proxy Manager that provides additional security, performance optimizations, and advanced features for reverse proxy and web server management. It includes built-in support for CrowdSec integration. -::: - -## AppSec Component Setup - -### Collection installation - -To begin setting up the AppSec Component, the initial step is to install a relevant set of rules. - -We will utilize the [`crowdsecurity/appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection, which offers a wide range of rules aimed at identifying and preventing the exploitation of known vulnerabilities. - -This collection is regularly updated to include protection against newly discovered vulnerabilities. Upon installation, it receives automatic daily updates to ensure your protection is always current. - -We also install the [`crowdsecurity/appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection. This collection contains detection scenarios for generic attack vectors. It provides protection in cases where specific scenarios for vulnerabilities do not exist yet. - -:::info -You can always view the content of a [collection on the Hub](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). -::: - -:::note -In this guide, you'll install these collections inside the CrowdSec container after starting the stack. -::: - -### Setup the Acquisition - -NPMplus provides a Docker Compose file that includes both NPMplus and CrowdSec services. We need to configure the acquisition for AppSec and NPMplus log parsing. +- **Docker** and **Docker Compose** installed. +- Ports **80/TCP, 443/TCP, 443/UDP** exposed to the internet; **81/TCP** available for the admin interface (can stay internal). +- A text editor and `curl` available on the host. -The AppSec part of this file is the AppSec acquisition datasource (`source: appsec`). For the complete reference of available keys, see the [AppSec datasource](/log_processor/data_sources/appsec.md). - -**Steps:** - -1. Download the compose.yaml file: +## 1. Download the NPMplus compose file ```bash -curl -L https://raw.githubusercontent.com/ZoeyVid/NPMplus/refs/heads/develop/compose.yaml -o compose.yaml +curl -L https://raw.githubusercontent.com/ZoeyVid/NPMplus/refs/heads/develop/compose.yaml \ + -o compose.yaml ``` -2. Edit the `compose.yaml` file with your preferred text editor: - - - **For the NPMplus service**: Set the environment variables: - - `TZ`: Your timezone (e.g., `TZ=Europe/Berlin`) - - `ACME_EMAIL`: Your email address for Let's Encrypt (e.g., `ACME_EMAIL=admin@example.org`) - - `LOGROTATE`: Set to `true` (uncomment this line). This is required for CrowdSec to parse NPMplus logs. - - - **For the CrowdSec service**: Uncomment the `crowdsec` service block. Make sure to keep the `openappsec` line commented (note: `appsec` and `openappsec` are different things). +## 2. Edit `compose.yaml` -3. Create the acquisition directory and configuration file: +Open the file and apply the following changes — none of these can be automated because you need to choose values for your environment: - The exact path depends on how volumes are mounted in your `compose.yaml`. Typically, you'll need to create the file in the location where CrowdSec's configuration is persisted. If the compose file mounts `/opt/crowdsec` or `/etc/crowdsec` from the host, create the directory and file there: +- **NPMplus service** — set the environment variables: + - `TZ` — your timezone (e.g. `Europe/Berlin`). + - `ACME_EMAIL` — your email for Let's Encrypt (e.g. `admin@example.org`). + - `LOGROTATE=true` — uncomment this line. Required for CrowdSec to parse NPMplus logs. +- **CrowdSec service** — uncomment the `crowdsec` service block. Leave the `openappsec` line commented (`appsec` and `openappsec` are different things). -```bash -# Adjust the path based on your Docker volume mounts -mkdir -p /opt/crowdsec/conf/acquis.d -``` +## 3. Add the AppSec acquisition - Alternatively, if you're using a different volume mount path, adjust accordingly. You can also create the file directly inside the container: +Create the acquisition file on the host; the path must match how you mount the CrowdSec config volume in `compose.yaml` (the default NPMplus compose uses `/opt/crowdsec/conf`): ```bash -docker exec -it crowdsec mkdir -p /etc/crowdsec/acquis.d -``` - -4. Create the acquisition configuration file `/opt/crowdsec/conf/acquis.d/npmplus.yaml` (or `/etc/crowdsec/acquis.d/npmplus.yaml` if using the container path) with the following content: - -```yaml title="/opt/crowdsec/conf/acquis.d/npmplus.yaml" +sudo mkdir -p /opt/crowdsec/conf/acquis.d +sudo tee /opt/crowdsec/conf/acquis.d/npmplus.yaml > /dev/null <<'EOF' filenames: - /opt/npmplus/nginx/*.log labels: @@ -109,126 +56,87 @@ name: appsec source: appsec labels: type: appsec +EOF ``` +The first two blocks parse NPMplus access logs; the third turns on the AppSec Component on `0.0.0.0:7422` (needed because CrowdSec is inside a container — exposure is still limited to the Docker network, **not** the internet). + :::info -You can find the newest version of the `npmplus.yaml` acquisition file [here](https://github.com/ZoeyVid/NPMplus). +The upstream `npmplus.yaml` can evolve; the latest reference is in the [NPMplus repo](https://github.com/ZoeyVid/NPMplus). ::: -**Configuration explained:** - -- The first two sections configure log parsing for NPMplus logs -- The third section configures the AppSec Component: - - `listen_addr: 0.0.0.0:7422`: The AppSec Component listens on all interfaces on port 7422 (needed for Docker networking) - - `appsec_configs`: Uses the [AppSec configuration(s)](/appsec/configuration.md) from the installed collections - - `source: appsec`: Identifies this as an AppSec data source - -### Running NPMplus and CrowdSec - -Start the services using Docker Compose: +## 4. Start the stack ```bash docker compose up -d ``` -### Install AppSec Collections - -After the containers have started, install the required AppSec collections inside the CrowdSec container: - -```bash -docker exec crowdsec cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules -``` - -This command installs the following items: -- The [*AppSec Rules*](/appsec/rules_syntax.md) contain the definition of malicious requests to be matched and stopped -- The [*AppSec Configuration*](/appsec/configuration.md#appsec-configuration-files) links together a set of rules to provide a coherent set -- The CrowdSec Parser and CrowdSec Scenario(s) are used to detect and remediate persistent attacks - -After installing the collections, restart the CrowdSec container to load the new configuration: +Install the AppSec collections inside the running CrowdSec container, then restart it so the new collections are picked up: ```bash +docker exec crowdsec cscli collections install \ + crowdsecurity/appsec-virtual-patching \ + crowdsecurity/appsec-generic-rules docker restart crowdsec ``` -:::warning Important -After starting NPMplus, wait about a minute, then check the logs to retrieve the initial admin password: +Retrieve the initial NPMplus admin password from its logs: ```bash -docker logs npmplus +sleep 60 && docker logs npmplus 2>&1 | grep -i password ``` -**Save this password** - you'll need it to log into the NPMplus admin interface. -::: - -## Remediation Component Setup - -Now we need to configure NPMplus to function as a Remediation Component for the Security Engine and enable the AppSec Component. +Save this password — you'll need it in step 5. -### Generate API Key +## 5. Enable AppSec in NPMplus -Generate an API key for NPMplus: +### Generate a bouncer API key ```bash docker exec crowdsec cscli bouncers add npmplus -o raw ``` -Copy the output API key - you'll need it in the next step. +Copy the printed key. ### Configure NPMplus -Edit the NPMplus CrowdSec configuration file: - -```bash -# The file location may vary depending on your Docker setup -# Typically it's at: /opt/npmplus/crowdsec/crowdsec.conf -``` - -In this file, you need to: - -1. Set `ENABLED=true` to enable the CrowdSec integration -2. Set `API_KEY` to the key you generated in the previous step - -The configuration file should look similar to: +Edit the NPMplus CrowdSec configuration file — its location depends on your compose mounts, typically `/opt/npmplus/crowdsec/crowdsec.conf`: -```ini +```ini title="/opt/npmplus/crowdsec/crowdsec.conf" ENABLED=true -API_KEY=your-api-key-here +API_KEY= ``` -### Restart NPMplus - -Restart the NPMplus container to apply the changes: +Restart NPMplus: ```bash docker restart npmplus ``` -### Verify Connection - -Check the Docker logs to confirm NPMplus is connected to CrowdSec: +Confirm NPMplus connects to CrowdSec: ```bash -docker logs npmplus +docker logs npmplus 2>&1 | grep -i crowdsec ``` -You should see lines mentioning that NPMplus is connected to CrowdSec. +## 6. Verify -## Testing the AppSec Component + Remediation Component +Hit an endpoint that should trip an AppSec rule (replace `localhost` with your server's address if different): -:::note -We're assuming the web server is accessible. Please adjust your testing accordingly. -::: +```bash +curl -I http://localhost/.env +``` -If you try to access `http://localhost/.env` (or your server's IP address) from a browser, your request will be blocked, resulting in the display of the following HTML page: +You should get an `HTTP/1.1 403 Forbidden` response. -![appsec-denied](/img/appsec_denied.png) +Check metrics inside the CrowdSec container: -We can also look at the metrics from `cscli metrics show appsec` - it will display: -- the number of requests processed by the AppSec Component -- Individual rule matches +```bash +docker exec crowdsec cscli metrics show appsec +```
- Example Output +Example metrics output ```bash title="docker exec crowdsec cscli metrics show appsec" Appsec Metrics: @@ -241,43 +149,35 @@ Appsec Metrics: Appsec '0.0.0.0:7422/' Rules Metrics: ╭─────────────────────────────────┬───────────╮ │ Rule ID │ Triggered │ -├─────────────────────────────────┼─────────┤ +├─────────────────────────────────┼───────────┤ │ crowdsecurity/vpatch-env-access │ 1 │ ╰─────────────────────────────────┴───────────╯ ``` -You can test and investigate further with [Stack Health-Check](/u/getting_started/health_check) and [Appsec Troubleshooting guide](/appsec/troubleshooting.md) -
-### Explanation +
+What just happened? + +1. `curl` hit NPMplus at `/.env`. +2. The NPMplus bouncer forwarded the request to the AppSec Component inside the Docker network (on `crowdsec:7422`). +3. AppSec matched the [`vpatch-env-access`](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) rule and answered `403`. +4. NPMplus served the ban page. -What happened in the test that we just did is: +
-1. We did a request (`localhost/.env`) to our web server -2. Thanks to the NPMplus Remediation Component configuration, the request was forwarded to `http://crowdsec:7422` (or the appropriate Docker network address) -3. Our AppSec Component, listening on `0.0.0.0:7422` analyzed the request -4. The request matches the [AppSec rule to detect .env access](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access) -5. The AppSec Component thus answered with [HTTP 403](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403) to the Remediation Component, indicating that the request must be blocked -6. The web server then presented us with the default "request blocked" page. +## Log into the NPMplus admin UI -## Integration with the Console +Open `https://:81` and log in with the `ACME_EMAIL` you set in step 2 and the password you saved in step 4. You'll be prompted to change both on first login. -If you haven't yet, follow the guide about [how to enroll your Security Engine in the Console](/u/getting_started/post_installation/console). +## Monitor in the Console -Once done, all your alerts, including the ones generated by the AppSec Component, appear in the Console: +If you haven't enrolled the Security Engine yet, follow [how to enroll in the Console](/u/getting_started/post_installation/console). Once enrolled, AppSec alerts appear alongside the rest of your alerts: ![appsec-console](/img/appsec_console.png) ## Next steps -You are now running the AppSec Component on your CrowdSec Security Engine with NPMplus, congrats! - -:::info -You can now log into the NPMplus admin interface at `https://:81` using the email address you configured (`ACME_EMAIL`) and the password you saved earlier. You should be prompted to change these credentials on first login. -::: - -As the next steps, you can: - - Look at [WAF Deployment Strategies](/appsec/advanced_deployments.mdx) to discover how to gradually improve your WAF security. - - Look at the [Rules syntax](/appsec/rules_syntax.md) and [creation process](/appsec/create_rules.md) to create your own and contribute - - Take a look at [the benchmarks](/appsec/benchmark.md) +- Monitor WAF alerts with `docker exec crowdsec cscli alerts list` or in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/traefik.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/traefik.mdx index 9b7aee925..4eda5c4cd 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/traefik.mdx @@ -470,6 +470,6 @@ Once done, all your alerts, including the ones generated by the AppSec Component You are now running the AppSec Component on your CrowdSec Security Engine. As the next steps, you can: - - Look at [WAF Deployment Strategies](/appsec/advanced_deployments.mdx) to discover how to gradually improve your WAF security. - - Look at the [Rules syntax](/appsec/rules_syntax.md) and [creation process](/appsec/create_rules.md) to create your own and contribute - - Take a look at [the benchmarks](/appsec/benchmark.md) +- Monitor WAF alerts in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/wordpress.mdx b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/wordpress.mdx index 2c9f76874..e1699359a 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/wordpress.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/quickstart/wordpress.mdx @@ -3,266 +3,89 @@ id: wordpress title: QuickStart - WordPress --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import CodeBlock from '@theme/CodeBlock'; -import UnderlineTooltip from '@site/src/components/underline-tooltip'; - # CrowdSec WAF QuickStart for WordPress -## Objectives - -The goal of this quickstart is to set up the [AppSec Component](/appsec/intro.md#introduction) to safeguard web applications running on [WordPress](https://wordpress.org) sites. - -We'll deploy a [set of rules](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) designed to block [well-known attacks](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) and [currently exploited vulnerabilities](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). - -Additionally, we'll show how to monitor these alerts through the [Console](https://app.crowdsec.net/). +Protect a [WordPress](https://wordpress.org) site with CrowdSec's [AppSec (WAF) Component](/appsec/intro.md#introduction). The WordPress bouncer is a WordPress plugin, so step 3 is a short click-through in `wp-admin`; everything else is copy-paste on the host running CrowdSec. ## Prerequisites -1. If you're new to the [AppSec Component](/appsec/intro.md#introduction) or **W**eb **A**pplication **F**irewalls, start with the [Introduction](/appsec/intro.md#introduction) for a better understanding. - -2. It's assumed that you have already installed: - - **CrowdSec [Security Engine](/intro.mdx)**: for installation, refer to the [QuickStart guide](/u/getting_started/installation/linux). The AppSec Component, which analyzes HTTP requests, is included within the security engine as a [Acquisition](/log_processor/data_sources/appsec.md). - - **WordPress [Remediation Component](/u/bouncers/intro)**: installation instructions are available in the [WordPress bouncer guide](/u/bouncers/wordpress). The CrowdSec WordPress plugin enables you to protect your WordPress site against malicious traffic using CrowdSec's advanced threat detection and blocklist capabilities. - - This component intercepts HTTP requests at the WordPress level and forwards them to the AppSec Component for analysis and action. - -:::tip Already did the base setup? -If you already completed the [General Setup](general.mdx) (collections + acquisition), skip to [Remediation Component Setup](#remediation-component-setup). -::: - -## AppSec Component Setup - -### Collection installation - -To begin setting up the AppSec Component, the initial step is to install a relevant set of rules. - -We will utilize the [`crowdsecurity/appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection, which offers a wide range of rules aimed at identifying and preventing the exploitation of known vulnerabilities. - -This collection is regularly updated to include protection against newly discovered vulnerabilities. Upon installation, it receives automatic daily updates to ensure your protection is always current. -We also install the [`crowdsecurity/appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection. This collection contains detection scenarios for generic attack vectors. It provides protection in cases where specific scenarios for vulnerabilities do not exist yet. +Make sure the following are already done (each is a single-page install guide): -On the machine where the Security Engine is installed, just execute the following command: +1. **CrowdSec Security Engine** installed and running — see the [Linux quickstart](/u/getting_started/installation/linux). +2. **WordPress bouncer plugin** installed and registered against the CrowdSec LAPI — see the [WordPress bouncer guide](/u/bouncers/wordpress). -:::info -You can always view the content of a [collection on the Hub](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching). -::: +## 1. Install the AppSec rule collections ```bash -sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules +sudo cscli collections install \ + crowdsecurity/appsec-virtual-patching \ + crowdsecurity/appsec-generic-rules ``` -Executing this command will install the following items: - -- The [*AppSec Rules*](/appsec/rules_syntax.md) contain the definition of malicious requests to be matched and stopped -- The [*AppSec Configuration*](/appsec/configuration.md#appsec-configuration-files) links together a set of rules to provide a coherent set -- The CrowdSec Parser and CrowdSec Scenario(s) bans for a longer duration repeating offenders - -### Setup the Acquisition - -Having installed the required components, it's time to configure the CrowdSec acquisition datasource for the AppSec Component ([AppSec datasource](/log_processor/data_sources/appsec.md)). This configuration allows WordPress to send requests to the AppSec Component for evaluation and decision-making. - -Steps: - -1. Create the acquisition directory (if it doesn't exist on your machine): - ```bash - sudo mkdir -p /etc/crowdsec/acquis.d/ - ``` +This pulls the [`appsec-virtual-patching`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-virtual-patching) collection (rules for known CVEs, auto-updated daily) and the [`appsec-generic-rules`](https://app.crowdsec.net/hub/author/crowdsecurity/collections/appsec-generic-rules) collection (common attack patterns), plus the default AppSec configuration. -2. Create `/etc/crowdsec/acquis.d/appsec.yaml`: - ```yaml title="/etc/crowdsec/acquis.d/appsec.yaml" - appsec_configs: - - crowdsecurity/appsec-default - labels: - type: appsec - listen_addr: 127.0.0.1:7422 - source: appsec - ``` - -The two important directives in this configuration file are: - - - `appsec_configs` is the list of [*AppSec Configurations*](/appsec/configuration.md#appsec-configuration-files) that was included in the Collection we just installed. - - the `listen_addr` is the IP and port the AppSec Component will listen to. - -:::warning -We do not recommend exposing the AppSec Component to the internet. It should only be accessible from the web server or WordPress application. -::: - -:::info -You can find more about the [supported options for the acquisition here](/log_processor/data_sources/appsec.md) -::: +## 2. Turn on the AppSec Component -You can now restart CrowdSec: +Create the acquisition file, then restart CrowdSec: ```bash +sudo mkdir -p /etc/crowdsec/acquis.d +sudo tee /etc/crowdsec/acquis.d/appsec.yaml > /dev/null <<'EOF' +appsec_configs: + - crowdsecurity/appsec-default +labels: + type: appsec +listen_addr: 127.0.0.1:7422 +source: appsec +EOF sudo systemctl restart crowdsec ``` -#### Testing the AppSec Component - -##### Verify the AppSec Component is listening - -To verify that the AppSec Component is running correctly, we can first check that the port `7422` is open and listening: - -:::note -If you have changed the port in the configuration file, replace `7422` with the new port number. -::: - - - - - sudo netstat -tlpn | grep 7422 - - - - sudo ss -tlpn | grep 7422 - - - -
- -Output example - -```bash -tcp 0 0 127.0.0.1:7422 0.0.0.0:* LISTEN 12345/crowdsec -``` - -:::note -The output may look differently depending on which command you used but as long as you see the port and the process `crowdsec`, it means the AppSec Component is running. +:::warning +Keep `listen_addr` on `127.0.0.1` — the AppSec Component must not be reachable from the internet. It should only be queried by your local WordPress instance. ::: -
- -##### (Optional) Manually testing the AppSec Component with `curl` +## 3. Enable AppSec in the WordPress plugin -
- Expand for short guide +This step uses the plugin's admin UI (no shell command): -Before we proceed with configuring the Remediation Component, let's verify that all our current setups are functioning correctly. - -1. Create a Remediation Component (Bouncer) API Key: - -```bash -sudo cscli bouncers add test_waf -k this_is_a_bad_password -API key for 'test_waf': +1. Log in to your WordPress admin panel. +2. Open **CrowdSec** in your admin menu and go to the **Advanced** section. +3. In the **AppSec component** block: + - **Enable AppSec**: check the box. + - **URL**: `http://127.0.0.1:7422` (or your AppSec Component address if CrowdSec runs elsewhere). + - **Request timeout**: `400` ms (default). + - **Fallback to**: `captcha` (recommended). + - **Maximum body size**: `1024` KB (default). + - **Body size exceeded action**: `headers_only` (recommended). +4. Save the settings. - this_is_a_bad_password - -Please keep this key since you will not be able to retrieve it! -``` - -2. Emit a legitimate request to the AppSec Component: - -```bash -curl -X POST localhost:7422/ -i -H 'x-crowdsec-appsec-uri: /test' -H 'x-crowdsec-appsec-ip: 192.168.1.1' -H 'x-crowdsec-appsec-host: foobar.com' -H 'x-crowdsec-appsec-verb: POST' -H 'x-crowdsec-appsec-api-key: this_is_a_bad_password' -``` - -Which will give us an answer such as: - -```bash -HTTP/1.1 200 OK -Date: Tue, 30 Jan 2024 15:43:50 GMT -Content-Length: 36 -Content-Type: text/plain; charset=utf-8 - -{"action":"allow","http_status":200} -``` - -3. Emit a malevolent request to the Appsec Component: +![appsec-config](/img/bouncer/wordpress/screenshots/config-appsec.png) :::info -We're trying to access a `.env` file, a [common way to retrieve credentials left by mistake](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-env-access). +AppSec requires the WordPress plugin to use API-key authentication (not TLS certificates). The AppSec Component is only consulted when LAPI returns a bypass decision. ::: -```bash -curl -X POST localhost:7422/ -i -H 'x-crowdsec-appsec-uri: /.env' -H 'x-crowdsec-appsec-ip: 192.168.1.1' -H 'x-crowdsec-appsec-host: foobar.com' -H 'x-crowdsec-appsec-verb: POST' -H 'x-crowdsec-appsec-api-key: this_is_a_bad_password' - -``` - -Our request is detected and blocked by the AppSec Component: - -```bash -HTTP/1.1 403 Forbidden -Date: Tue, 30 Jan 2024 15:57:08 GMT -Content-Length: 34 -Content-Type: text/plain; charset=utf-8 - -{"action":"ban","http_status":403} -``` +## 4. Verify -Let's now delete our test API Key: +From any machine, send a request with a malicious body through WordPress — this example trips the [`vpatch-CVE-2022-22965`](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-CVE-2022-22965) rule (Spring4Shell): ```bash -sudo cscli bouncers delete test_waf +curl -X POST https:/// \ + -d "class.module.classLoader.resources." \ + -o /dev/null -s -w "%{http_code}\n" ``` -
- -## Remediation Component Setup - -Since our AppSec Component is active and listening, we can now configure the WordPress Remediation Component to forward requests to it. - -The WordPress bouncer includes built-in AppSec support that can be enabled through the plugin's admin interface. - -### Enable AppSec in WordPress Plugin +You should get `403` printed. -1. Log in to your WordPress admin panel -2. Navigate to the CrowdSec plugin settings (`CrowdSec` in your admin menu) -3. Go to the `Advanced` section -4. Find the `AppSec component` configuration section -5. Enable AppSec and configure the connection: - - - **Enable AppSec**: Check this box to enable AppSec functionality - - **URL**: Set to `http://127.0.0.1:7422` (or your custom AppSec Component address) - - **Request timeout**: Default is 400 milliseconds (adjust as needed) - - **Fallback to**: Choose `captcha` (recommended) for when AppSec calls fail - - **Maximum body size**: Default is 1024 KB - - **Body size exceeded action**: Choose `headers_only` (recommended) - - -![appsec-config](/img/bouncer/wordpress/screenshots/config-appsec.png) - -:::info -AppSec functionality is only available when using API key authentication (not TLS certificates) in the WordPress plugin. -::: - -:::note -The AppSec Component will only be consulted when the initial LAPI remediation returns a bypass decision. -::: - -## Testing the AppSec Component + Remediation Component - -:::note -We're assuming WordPress is running on your local machine. Please adjust your testing accordingly if this is not the case. -::: - -To test the AppSec functionality, you need to make a request that will go through the WordPress loading process. Try accessing a WordPress page with a malicious payload in the URL parameters or body. -For example, we can post a request with a body that contains a malicious payload, such as a [Remote Code Execution (CVE-2022-22965)](https://app.crowdsec.net/hub/author/crowdsecurity/appsec-rules/vpatch-CVE-2022-22965) attempt. +Check that CrowdSec recorded the block: ```bash -curl -X POST https:/// -d "class.module.classLoader.resources." -o /dev/null -s -w "%{http_code}" +sudo cscli metrics show appsec ``` - -When the AppSec Component detects such a malicious request, you'll see that the response is a 403 (Forbidden) status code, indicating that the request was blocked. - -If your test is not successful, please refer to the [Health check and troubleshoot guide](/u/getting_started/health_check/) for help. - - -You can also look at the metrics from `cscli metrics show appsec` which will display: - - the number of requests processed by the AppSec Component - - Individual rule matches - -
- Example Output - +
+Example metrics output ```bash title="sudo cscli metrics show appsec" Appsec Metrics: @@ -282,44 +105,30 @@ Appsec '127.0.0.1:7422/' Rules Metrics:
-### Explanation - -What happened in the test that we just did is: - - 1. We made a request with malicious payload to our WordPress site - 2. The WordPress bouncer plugin intercepted the request as part of the WordPress loading process - 3. The bouncer first checked with the local CrowdSec API for any existing decisions - 4. Since there was no existing ban decision, the bouncer forwarded the request to the AppSec Component at `http://127.0.0.1:7422` - 5. Our AppSec Component analyzed the request and matched it against the appropriate AppSec rules (here `crowdsecurity/vpatch-CVE-2022-22965` rule) - 6. The AppSec Component returned an HTTP 403 response to the WordPress bouncer, indicating that the request must be blocked - 7. The WordPress bouncer then presented the visitor with the configured ban page - -## Integration with the Console - -If you haven't yet, follow the guide about [how to enroll your Security Engine in the Console](/u/getting_started/post_installation/console). - -Once done, all your alerts, including the ones generated by the AppSec Component, appear in the Console: - -![appsec-console](/img/appsec_console.png) +
+What just happened? -## WordPress-Specific Considerations +1. `curl` sent a request with a malicious payload to WordPress. +2. The CrowdSec plugin intercepted the request inside the WordPress loading process. +3. LAPI had no existing ban, so the plugin forwarded the request to the AppSec Component at `http://127.0.0.1:7422`. +4. The request matched the `vpatch-CVE-2022-22965` rule. +5. AppSec answered `403`; the plugin served the configured ban page. -### Understanding Plugin Limitations +
-The WordPress bouncer has some inherent limitations you should be aware of: +## WordPress-specific limits -1. **WordPress Loading Process**: The plugin only protects requests that go through the WordPress core loading process. Direct access to PHP files outside of WordPress won't be protected. +- The plugin only protects requests that go through the WordPress core loading process. Direct hits to PHP files outside WordPress — and any non-PHP file like `.env` or `.sql` — bypass it. +- For broader coverage, enable [auto prepend file mode](/u/bouncers/wordpress#auto-prepend-file-mode) in the plugin settings. -2. **Static Files**: Requests for non-PHP files (like `.env`, `.sql`, or other static files) won't be processed by the plugin since they don't go through PHP. +## Monitor in the Console -3. **Auto Prepend File Mode**: For comprehensive protection, consider enabling [auto prepend file mode](/u/bouncers/wordpress#auto-prepend-file-mode) in the plugin settings to ensure all PHP scripts are protected. +If you haven't enrolled the Security Engine yet, follow [how to enroll in the Console](/u/getting_started/post_installation/console). Once enrolled, AppSec alerts appear alongside the rest of your alerts: +![appsec-console](/img/appsec_console.png) ## Next steps -You are now running the AppSec Component on your CrowdSec Security Engine. - -As the next steps, you can: - - Look at [WAF Deployment Strategies](/appsec/advanced_deployments.mdx) to discover how to gradually improve your WAF security. - - Look at the [Rules syntax](/appsec/rules_syntax.md) and [creation process](/appsec/create_rules.md) to create your own and contribute - - Take a look at [the benchmarks](/appsec/benchmark.md) +- Monitor WAF alerts with `sudo cscli alerts list` or in the [CrowdSec Console](https://app.crowdsec.net). +- Review the [AppSec troubleshooting guide](/appsec/troubleshooting.md) and the [WordPress bouncer docs](/u/bouncers/wordpress) if you need to investigate or refine the deployment. +- Explore [WAF deployment strategies](/appsec/advanced_deployments.mdx), [rules syntax](/appsec/rules_syntax.md), [rule creation](/appsec/create_rules.md), and [benchmarks](/appsec/benchmark.md) to go further. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_deploy.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_deploy.md index f2aa80dd2..98bb26926 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_deploy.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_deploy.md @@ -40,7 +40,7 @@ labels: Once the rule behaves as expected, the remaining steps package it for CrowdSec, wire it into the acquisition pipeline, and test it end to end. -## Step 1 — Stage the Rule File +## Step 1 - Stage the Rule File CrowdSec loads AppSec rules from `/etc/crowdsec/appsec-rules/`. Copy your YAML rule into that directory (create a `custom/` subfolder to keep things tidy if you manage several rules): @@ -56,7 +56,7 @@ Make sure the `name` inside the rule file matches the file name convention you p If you run CrowdSec in a container, copy the file into the volume that is mounted at `/etc/crowdsec/appsec-rules/` inside the container. ::: -## Step 2 — Create an AppSec Configuration +## Step 2 - Create an AppSec Configuration An AppSec configuration lists which rules to load and how to handle matches. Create a new file under `/etc/crowdsec/appsec-configs/` that targets your custom rule: @@ -73,7 +73,7 @@ Key points: - `inband_rules` (and/or `outofband_rules`) accept glob patterns, so you can load multiple rules with a single entry such as `custom/block-*`. - During the reload step CrowdSec validates the syntax; if anything is off, the reload fails and the service logs the parsing error. -## Step 3 — Reference the Configuration in the Acquisition File +## Step 3 - Reference the Configuration in the Acquisition File The AppSec acquisition file (`/etc/crowdsec/acquis.d/appsec.yaml`) controls which configurations are active for the WAF component. Add your configuration to the `appsec_configs` list. Order matters: later entries override conflicting defaults such as `default_remediation`. @@ -89,7 +89,7 @@ source: appsec If you only want to run your custom configuration, remove other entries and keep the list with a single item. -## Step 4 — Reload CrowdSec and Validate the Load +## Step 4 - Reload CrowdSec and Validate the Load Apply the changes by reloading the CrowdSec service: @@ -106,7 +106,7 @@ sudo cscli appsec-configs list | grep block-nonnumeric-user-id The rule should appear as `enabled`, and the configuration should show up in the list. CrowdSec logs confirm the configuration was loaded without errors. -## Step 5 — Functional Test with `curl` +## Step 5 - Functional Test with `curl` Trigger the behaviour your rule is meant to catch to ensure it blocks as expected. For the example rule, send a request with a non-numeric `user_id` value: diff --git a/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_examples.md b/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_examples.md index 38c8ab05b..e5350d2b1 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_examples.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/appsec/rules_examples.md @@ -507,6 +507,29 @@ label=aaa\u0027%2b#request.get(\u0027.KEY_velocity.struts2.context\u0027).intern Hooks allow you to customize WAF behavior at different execution phases. This section demonstrates key hook capabilities organized by execution phase. +## Load Phase (on_load) + +Load hooks run once when the configuration is loaded, and are typically used to apply global settings. + +### 1. Tune Request Body Size Handling + +#### Description + +Change the maximum request body size buffered and inspected by the engine, and what happens when a request exceeds it. + +#### Hook Example + +```yaml +on_load: + - apply: + - SetMaxBodySize(20971520) # 20MB + - SetBodySizeExceededAction("partial") +``` + +#### Use Case + +Allow larger uploads on this configuration while still bounding memory usage, and inspect the first 20MB of oversized bodies instead of dropping the request outright. See [Request body size handling](hooks.md#request-body-size-handling) for the available actions (`drop`, `partial`, `allow`). + ## Pre-Evaluation Phase (pre_eval) Pre-evaluation hooks run before rules are evaluated, allowing you to modify rule behavior dynamically per request. @@ -617,6 +640,25 @@ pre_eval: Automatically block traffic from unwanted countries. +### 6. Disable Body Inspection for Specific Requests + +#### Description + +Skip request body inspection for the current request, for example on endpoints that legitimately receive large uploads. + +#### Hook Example + +```yaml +pre_eval: + - filter: req.URL.Path startsWith "/upload" + apply: + - DisableBodyInspection() +``` + +#### Use Case + +Avoid buffering and inspecting large file uploads on trusted endpoints. This also bypasses the [maximum body size check](hooks.md#request-body-size-handling), so requests exceeding the limit are allowed through instead of being dropped. + ## Post-Evaluation Phase (post_eval) Post-evaluation hooks run after rule evaluation is complete, primarily used for debugging and logging. diff --git a/crowdsec-docs/versioned_docs/version-v1.7/configuration/network_management.md b/crowdsec-docs/versioned_docs/version-v1.7/configuration/network_management.md index 5d68ad496..da43caf40 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/configuration/network_management.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/configuration/network_management.md @@ -55,3 +55,7 @@ Both components need proper configuration to run (we decide to keep this behavio ## Prometheus -> Agents - If you're scrapping prometheus metrics from your agents or your local API, you need to allow inbound connections to `tcp/6060` + +## Notes on proxy use + + - It's possible to use crowdsec through proxy, it will honor the `HTTP_PROXY` environment variable. More on the configuration how to use crowdsec through a proxy [here](/u/troubleshooting/security_engine#how-to-set-up-a-proxy) diff --git a/crowdsec-docs/versioned_docs/version-v1.7/getting_started/sdk_intro.mdx b/crowdsec-docs/versioned_docs/version-v1.7/getting_started/sdk_intro.mdx index a2d46fe37..16f10de0a 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/getting_started/sdk_intro.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/getting_started/sdk_intro.mdx @@ -9,9 +9,9 @@ CrowdSec offers lightweight SDKs for Python and PHP to help developers seamlessl By using these SDKs, you can report signals such as suspicious IP activity or confirmed attacks directly to the Central API (CAPI). In return, your users gain access to the CrowdSec Community Blocklist, a curated and constantly updated list of IPs involved in malicious behavior observed across the global CrowdSec network. Why Integrate the SDK: -- **Simple Integration** — Add signal sharing with just a few lines of code -- **Community-Powered Protection** — Contributions help power our global threat intelligence network -- **Mutual Benefit** — Your platform shares valuable intelligence and gains stronger real-time protection in return +- **Simple Integration**: Add signal sharing with just a few lines of code +- **Community-Powered Protection**: Contributions help power our global threat intelligence network +- **Mutual Benefit**: Your platform shares valuable intelligence and gains stronger real-time protection in return ## Supported SDKs diff --git a/crowdsec-docs/versioned_docs/version-v1.7/intro.mdx b/crowdsec-docs/versioned_docs/version-v1.7/intro.mdx index 9ce915992..04890256e 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/intro.mdx +++ b/crowdsec-docs/versioned_docs/version-v1.7/intro.mdx @@ -54,7 +54,7 @@ Under the hood, the Security Engine has various components: - The [Local API](local_api/intro.md) acts as a middleman: - Between the [Log Processors](/log_processor/intro.mdx) and the [Remediation Components](/u/bouncers/intro) which are in charge of enforcing decisions. - And with the [Central API](/central_api/intro.md) to share alerts and receive blocklists. -- The [Remediation Components](/u/bouncers/intro) (also called bouncers) block malicious IPs at your chosen level—IpTables, firewalls, web servers, or reverse proxies. [See the full list on the CrowdSec Hub.](https://app.crowdsec.net/hub/remediation-components) +- The [Remediation Components](/u/bouncers/intro) (also called bouncers) block malicious IPs at your chosen level: IpTables, firewalls, web servers, or reverse proxies. [See the full list on the CrowdSec Hub.](https://app.crowdsec.net/hub/remediation-components) ## Deployment options diff --git a/crowdsec-docs/versioned_docs/version-v1.7/local_api/database.md b/crowdsec-docs/versioned_docs/version-v1.7/local_api/database.md index 9da286807..08b3f4f90 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/local_api/database.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/local_api/database.md @@ -12,7 +12,7 @@ Please refer to [ent.](https://entgo.io/) [supported database](https://entgo.io/ - MySQL `5.6.35`, `5.7.26` and `8` - MariaDB `10.2`, `10.3` and latest - - PostgreSQL `11`, `12`, `13`, `14` and `15` + - PostgreSQL `13`, `14`, `15`, `16`, and `17`. - SQLite - Gremlin diff --git a/crowdsec-docs/versioned_docs/version-v1.7/log_processor/data_sources/appsec.md b/crowdsec-docs/versioned_docs/version-v1.7/log_processor/data_sources/appsec.md index 8b38aae3d..0d783c409 100644 --- a/crowdsec-docs/versioned_docs/version-v1.7/log_processor/data_sources/appsec.md +++ b/crowdsec-docs/versioned_docs/version-v1.7/log_processor/data_sources/appsec.md @@ -57,6 +57,12 @@ Number of routines to use to process the requests. Defaults to 1. How long to cache the auth token for. Accepts value supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration). Defaults to 1m. +### `body_read_timeout` + +How long to wait for the remediation component to finish sending the request body before giving up and processing whatever was received. Accepts value supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration). +Set to `0` to disable the timeout. +Defaults to 1s. + ### `cert_file` Path to the cert file to allow HTTPS communication between the remediation component and the appsec component.