diff --git a/docs/configuration-guides/allowlist.md b/docs/configuration-guides/allowlist.md index 2556270..87584ff 100644 --- a/docs/configuration-guides/allowlist.md +++ b/docs/configuration-guides/allowlist.md @@ -1,6 +1,6 @@ # Allowlisting IPs -The Wallarm API Firewall enables secure access to your backend by allowing requests exclusively from predefined IP addresses. This document provides a step-by-step guide on how to implement IP allowlisting, applicable for the [REST API in the `PROXY` mode](../installation-guides/docker-container.md) or [GraphQL API](../installation-guides/graphql/docker-container.md). +The Wallarm API Firewall enables secure access to your backend by allowing requests exclusively from predefined IP addresses. This document provides a step-by-step guide on how to implement IP allowlisting, applicable for the REST API in both the [`PROXY`](../installation-guides/docker-container.md) and [`API`](../installation-guides/api-mode.md) modes or for [GraphQL API](../installation-guides/graphql/docker-container.md). This feature ensures that only requests from allowlisted IP addresses are validated against the OpenAPI specification 3.0. Requests from non-allowlisted IPs are outright rejected, returning a 403 error code, regardless of their compliance with the OpenAPI specification. @@ -10,13 +10,16 @@ To allowlist IP addresses: ``` 1.1.1.1 - 2.2.2.2 + 2001:0db8:11a3:09d7:1f34:8a2e:07a0:7655 + 10.1.2.0/24 ``` + The requests from 1.1.1.1, 2001:0db8:11a3:09d7:1f34:8a2e:07a0:7655 and 10.1.2.1-10.1.2.254 IPs will be allowed. + !!! info "Allowlist validation and supported data formats" - The API Firewall does not perform content validation on the allowlist file during list handling. + The API Firewall validates the content of the allowlist file during list handling. - It supports both IPv4 and IPv6 addresses, but does not support subnets. + It supports both IPv4 and IPv6 addresses, as well as subnets. 1. Mount the allowlist file to the API Firewall Docker container using the `-v` Docker option. 1. Run the API Firewall container with the `APIFW_ALLOW_IP_FILE` environment variable indicating the path to the mounted allowlist file inside the container. 1. (Optional) Pass to the container the `APIFW_ALLOW_IP_HEADER_NAME` environment variable with the name of the request header that carries the origin IP address, if necessary. By default, `connection.remoteAddress` is used (the variable value is empty). @@ -30,7 +33,7 @@ docker run --rm -it --network api-firewall-network --network-alias api-firewall -e APIFW_URL= -e APIFW_SERVER_URL= \ -e APIFW_REQUEST_VALIDATION= -e APIFW_RESPONSE_VALIDATION= \ -e APIFW_ALLOW_IP_FILE=/opt/ip-allowlist.txt -e APIFW_ALLOW_IP_HEADER_NAME="X-Real-IP" \ - -p 8088:8088 wallarm/api-firewall:v0.6.16 + -p 8088:8088 wallarm/api-firewall:v0.6.17 ``` | Environment variable | Description | diff --git a/docs/installation-guides/api-mode.md b/docs/installation-guides/api-mode.md index 95bdf71..95de2e8 100644 --- a/docs/installation-guides/api-mode.md +++ b/docs/installation-guides/api-mode.md @@ -8,12 +8,27 @@ If you need to validate individual API requests based on a given OpenAPI specifi ## Requirements * [Installed and configured Docker](https://docs.docker.com/get-docker/) -* [SQLite database](https://www.sqlite.org/index.html) with the `openapi_schemas` table containing one or more [OpenAPI 3.0 specifications](https://swagger.io/specification/). The table should adhere to the following schema: - - * `schema_id`, integer (auto-increment) - ID of the specification. - * `schema_version`, string - Specification version. You can assign any preferred version. When this field changes, API Firewall assumes the specification itself has changed and updates it accordingly. - * `schema_format`, string - The specification format, can be `json` or `yaml`. - * `schema_content`, string - The specification content. +* [SQLite database](https://www.sqlite.org/index.html) with the table containing one or more [OpenAPI 3.0 specifications](https://swagger.io/specification/). The database can be of one of the following formats: + + === "SQLite database V1" + * Table name is `openapi_schemas`. + * `schema_id`, integer (auto-increment) - ID of the specification. + * `schema_version`, string - Specification version. You can assign any preferred version. When this field changes, API Firewall assumes the specification itself has changed and updates it accordingly. + * `schema_format`, string - The specification format, can be `json` or `yaml`. + * `schema_content`, string - The specification content. + === "SQLite database V2" + Use this format if you need to control whether a specification from the database has been handled by the API Firewall or not. + + * Table name is `openapi_schemas`. + * `schema_id`, integer (auto-increment) - ID of the specification. + * `schema_version`, string - Specification version. You can assign any preferred version. When this field changes, API Firewall assumes the specification itself has changed and updates it accordingly. + * `schema_format`, string - The specification format, can be `json` or `yaml`. + * `schema_content`, string - The specification content. + * `status`, string - Specifies whether a specification is `new` (not yet processed) or `applied` (already processed). It is expected to be set to `new` by default. + + At startup, the API Firewall automatically updates processed specification status from `new` to `applied`. + + During the `APIFW_SPECIFICATION_UPDATE_PERIOD`, only specifications marked as `new` receive updates. ## Running the API Firewall container @@ -23,7 +38,7 @@ Use the following command to run the API Firewall container: ``` docker run --rm -it -v :/var/lib/wallarm-api/1/wallarm_api.db \ - -e APIFW_MODE=API -p 8282:8282 wallarm/api-firewall:v0.6.16 + -e APIFW_MODE=API -p 8282:8282 wallarm/api-firewall:v0.6.17 ``` You can pass to the container the following variables: @@ -39,6 +54,7 @@ You can pass to the container the following variables: | `APIFW_READ_TIMEOUT` | The timeout for API Firewall to read the full request (including the body). The default value is `5s`. | No | | `APIFW_WRITE_TIMEOUT` | The timeout for API Firewall to return the response to the request. The default value is `5s`. | No | | `APIFW_HEALTH_HOST` | The host of the health check service. The default value is `0.0.0.0:9667`. The liveness probe service path is `/v1/liveness` and the readiness service path is `/v1/readiness`. | No | +| `APIFW_API_MODE_DB_VERSION` | Determines the SQLite database version that the API Firewall is configured to use. Available options are:
  • `0` (default) - tries to load V2 (with the `status` field) first; if unsuccessful, attempts V1. On both failures, the firewall fails to start.
  • `1` - recognize and process the database as V1 only.
  • `2` - recognize and process the database as V2 only.
| No | ## Evaluating requests against the specification diff --git a/docs/installation-guides/docker-container.md b/docs/installation-guides/docker-container.md index be587ed..b90ad1e 100644 --- a/docs/installation-guides/docker-container.md +++ b/docs/installation-guides/docker-container.md @@ -27,7 +27,7 @@ networks: services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.6.16 + image: wallarm/api-firewall:v0.6.17 restart: on-failure volumes: - : @@ -153,6 +153,6 @@ To start API Firewall on Docker, you can also use regular Docker commands as in -v : -e APIFW_API_SPECS= \ -e APIFW_URL= -e APIFW_SERVER_URL= \ -e APIFW_REQUEST_VALIDATION= -e APIFW_RESPONSE_VALIDATION= \ - -p 8088:8088 wallarm/api-firewall:v0.6.16 + -p 8088:8088 wallarm/api-firewall:v0.6.17 ``` 4. When the environment is started, test it and enable traffic on API Firewall following steps 6 and 7. diff --git a/docs/installation-guides/graphql/docker-container.md b/docs/installation-guides/graphql/docker-container.md index 1b083bc..c7d910e 100644 --- a/docs/installation-guides/graphql/docker-container.md +++ b/docs/installation-guides/graphql/docker-container.md @@ -29,7 +29,7 @@ networks: services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.6.16 + image: wallarm/api-firewall:v0.6.17 restart: on-failure volumes: - : @@ -99,6 +99,7 @@ Pass API Firewall configuration in **docker-compose.yml** → `services.api-fire | `APIFW_GRAPHQL_MAX_ALIASES_NUM` | Sets a limit on the number of aliases that can be used in a GraphQL document. If this variable is set to `0`, it implies that there is no limit on the number of aliases that can be used. | Yes | | `APIFW_GRAPHQL_INTROSPECTION` | Allows introspection queries, which disclose the layout of your GraphQL schema. When set to `true`, these queries are permitted. | Yes | | `APIFW_GRAPHQL_FIELD_DUPLICATION` | Defines whether to allow or prevent the duplication of fields in a GraphQL document. The default value is `false` (prevent). | No | +| `APIFW_GRAPHQL_BATCH_QUERY_LIMIT` | Sets a limit on the number of queries that can be batched together in a single GraphQL request. If this variable is set to `0`, it implies that there is no limit on the number of batched queries. | No | | `APIFW_LOG_LEVEL` | API Firewall logging level. Possible values:
  • `DEBUG` to log events of any type (INFO, ERROR, WARNING, and DEBUG).
  • `INFO` to log events of the INFO, WARNING, and ERROR types.
  • `WARNING` to log events of the WARNING and ERROR types.
  • `ERROR` to log events of only the ERROR type.
  • `TRACE` to log incoming requests and API Firewall responses, including their content.
The default value is `DEBUG`. Logs on requests and responses that do not match the provided schema have the ERROR type. | No | | `APIFW_SERVER_DELETE_ACCEPT_ENCODING` | If it is set to `true`, the `Accept-Encoding` header is deleted from proxied requests. The default value is `false`. | No | | `APIFW_LOG_FORMAT` | The format of API Firewall logs. The value can be `TEXT` or `JSON`. The default value is `TEXT`. | No | @@ -129,21 +130,35 @@ With `APIFW_GRAPHQL_REQUEST_VALIDATION` set to `BLOCK`, the firewall works as fo * If the API Firewall cannot parse the request, it responds with the GraphQL error with a 500 status code. * If the validation fails by the API Firewall, it does not proxy the request to the backend server but responds to the client with 200 status code and GraphQL error in response. -If the request does not match the provided API schema, the appropriate ERROR message will be added to the API Firewall Docker container logs, e.g. in the JSON format: +If the request does not match the provided API schema: -```json -{ - "errors": [ +* The API Firewall returns the following response: + + ```json { - "message": "field: name not defined on type: Query", - "path": [ - "query", - "name" + "errors": [ + { + "message":"invalid query" + } ] } - ] -} -``` + ``` + +* The appropriate ERROR message is added to the API Firewall Docker container logs, e.g. in the JSON format: + + ```json + { + "errors": [ + { + "message": "field: name not defined on type: Query", + "path": [ + "query", + "name" + ] + } + ] + } + ``` In scenarios where multiple fields in the request are invalid, only a singular error message will be generated. @@ -184,6 +199,6 @@ To start API Firewall on Docker, you can also use regular Docker commands as in -e APIFW_GRAPHQL_MAX_QUERY_COMPLEXITY= \ -e APIFW_GRAPHQL_MAX_QUERY_DEPTH= -e APIFW_GRAPHQL_NODE_COUNT_LIMIT= \ -e APIFW_GRAPHQL_INTROSPECTION= \ - -p 8088:8088 wallarm/api-firewall:v0.6.16 + -p 8088:8088 wallarm/api-firewall:v0.6.17 ``` 4. When the environment is started, test it and enable traffic on API Firewall following steps 6 and 7. diff --git a/docs/installation-guides/graphql/limit-compliance.md b/docs/installation-guides/graphql/limit-compliance.md index 2a532c0..e1a5c67 100644 --- a/docs/installation-guides/graphql/limit-compliance.md +++ b/docs/installation-guides/graphql/limit-compliance.md @@ -9,8 +9,9 @@ When [running](docker-container.md) the API Firewall Docker container for a Grap | `APIFW_GRAPHQL_MAX_QUERY_COMPLEXITY` | Defines the maximum number of Node requests that might be needed to execute the query. Setting it to `0` disables the complexity check. | | `APIFW_GRAPHQL_MAX_QUERY_DEPTH` | Specifies the maximum permitted depth of a GraphQL query. A value of `0` means the query depth check is skipped. | | `APIFW_GRAPHQL_NODE_COUNT_LIMIT` | Sets the upper limit for the node count in a query. When set to `0`, the node count limit check is skipped. | -| `APIFW_GRAPHQL_MAX_ALIASES_NUM` | Sets a limit on the number of aliases that can be used in a GraphQL document. If this variable is set to `0`, it implies that there is no limit on the number of aliases that can be used. | Yes | +| `APIFW_GRAPHQL_MAX_ALIASES_NUM` | Sets a limit on the number of aliases that can be used in a GraphQL document. If this variable is set to `0`, it implies that there is no limit on the number of aliases that can be used. | | `APIFW_GRAPHQL_FIELD_DUPLICATION` | Defines whether to allow or prevent the duplication of fields in a GraphQL document. The default value is `false` (prevent). | +| `APIFW_GRAPHQL_BATCH_QUERY_LIMIT` | Sets a limit on the number of queries that can be batched together in a single GraphQL request. If this variable is set to `0`, it implies that there is no limit on the number of batched queries. | ## How limit calculation works @@ -288,3 +289,21 @@ fragment TypeRef on __Type { * Depth = {int} 0 Since the `__schema: __Schema! @nodeCountSkip` directive is present in the schema, the calculated NodeCount, Complexity, and Depth are all 0. + +### Example 6 (limiting batched queries) + +Assume you have set the `APIFW_GRAPHQL_BATCH_QUERY_LIMIT` environment variable to `2`. If you attempt to execute the following batch of 3 GraphQL queries sequentially against the backend: + +```json +[ + {"query":"query {\n systemHealth\n}","variables":[]}, + {"query":"query {\n systemHealth\n}","variables":[]}, + {"query":"query {\n systemHealth\n}","variables":[]} +] +``` + +The API Firewall will intercept this request and log an error, indicating that the number of queries in the batch exceeds the configured limit. The logged error message will be: + +``` +ERROR GraphQL query validation error=the batch query limit has been exceeded. The number of queries in the batch is 3. The current batch query limit is 2 protocol=HTTP +``` \ No newline at end of file diff --git a/docs/release-notes.md b/docs/release-notes.md index 450e993..93a6dfa 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,28 @@ This page describes new releases of Wallarm API Firewall. +## v0.6.17 (2024-03-28) + +* Added [IP allowlisting](configuration-guides/allowlist.md) support in the `API` mode +* ​​Added support for subnets in allowlisted IP file and IP address validation during the file upload +* Added support for a new SQLite database structure (V2) in the [`API`](installation-guides/api-mode.md) mode of the API Firewall. This version adds a `status` field to track specifications as `new` (unprocessed by the firewall) or `applied` (processed). + + For backward compatibility, the `APIFW_API_MODE_DB_VERSION` environment variable has been added - it defaults to attempting to parse the database as V2; if unsuccessful, it falls back to previous format (V1). +* Added the following default response from the API Firewall to GraphQL requests that do not match a provided API schema: + + + ```json + { + "errors": [ + { + "message":"invalid query" + } + ] + } + ``` +* Introduced the new environment variable to limit the number of queries that can be batched together in a single GraphQL request, `APIFW_GRAPHQL_BATCH_QUERY_LIMIT` +* Upgraded Go up to 1.21 and some other dependencies + ## v0.6.16 (2024-02-27) * Added IP allowlisting, enabling secure access to backends by allowing only requests from predefined IP addresses for both REST and GraphQL APIs. This update ensures requests from allowlisted IPs are validated against the OpenAPI specification 3.0, with non-allowlisted IP requests being rejected with a 403 error code. Thanks for [PR #76 contributors](https://github.com/wallarm/api-firewall/pull/76). [Read more](configuration-guides/allowlist.md) diff --git a/stylesheets-docs/extra.css b/stylesheets-docs/extra.css index f082137..cd93e34 100644 --- a/stylesheets-docs/extra.css +++ b/stylesheets-docs/extra.css @@ -285,11 +285,20 @@ svg.navigation-arrow { color: #3942EA; } +.md-typeset a>code { + color: #3942EA; +} + .md-typeset a:hover { color: #3942EA; text-decoration: underline; } +.md-typeset a:hover > code { + color: #3942EA; + text-decoration: underline; +} + .md-typeset a:hover>code { background-color: unset; }