Skip to content

Commit

Permalink
chore(readme): Add Coraza Proxy WASM as WasmPlugin for Istio Guide (#233
Browse files Browse the repository at this point in the history
)

Signed-off-by: Karsten Siemer <[email protected]>
  • Loading branch information
KarstenSiemer authored Oct 14, 2023
1 parent 0c05075 commit 02eda47
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 21 deletions.
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ Web Application Firewall WASM filter built on top of [Coraza](https://github.com
```bash
▶ go run mage.go -l
Targets:
build* builds the Coraza wasm plugin.
check runs lint and tests.
coverage runs tests with coverage and race detector enabled.
doc runs godoc, access at http://localhost:6060
e2e runs e2e tests with a built plugin against the example deployment.
format formats code in this repository.
ftw runs ftw tests with a built plugin and Envoy.
lint verifies code quality.
runExample spins up the test environment, access at http://localhost:8080.
teardownExample tears down the test environment.
test runs all unit tests.
build* builds the Coraza wasm plugin.
check runs lint and tests.
coverage runs tests with coverage and race detector enabled.
doc runs godoc, access at http://localhost:6060
e2e runs e2e tests with a built plugin against the example deployment.
format formats code in this repository.
ftw runs ftw tests with a built plugin and Envoy.
lint verifies code quality.
runEnvoyExample spins up the test environment, access at http://localhost:8080.
teardownEnvoyExample tears down the test environment.
ReloadEnvoyExample reloads the test environment.
test runs all unit tests.

* default target
```
Expand Down Expand Up @@ -155,7 +156,11 @@ FTW_INCLUDE=920410 go run mage.go ftw

## Example: Spinning up the coraza-wasm-filter for manual tests

Once the filter is built, via the commands `mage runExample`, `mage reloadExample`, and `mage teardownExample` you can spin up, test, and tear down the test environment. Envoy with the coraza-wasm filter will be reachable at `localhost:8080`. The filter is configured with the CRS loaded working in Anomaly Scoring mode. For details and locally tweaking the configuration refer to [@demo-conf](./wasmplugin/rules/coraza-demo.conf) and [@crs-setup-demo-conf](./wasmplugin/rules/crs-setup-demo.conf).
Once the filter is built, via the commands `mage runEnvoyExample`, `mage reloadEnvoyExample`, and `mage teardownEnvoyExample` you can spin up, test, and tear down the test environment.
Envoy with the coraza-wasm filter will be reachable at `localhost:8080`.
The filter is configured with the CRS loaded working in Anomaly Scoring mode.
For details and locally tweaking the configuration refer to [@demo-conf](./wasmplugin/rules/coraza-demo.conf) and [@crs-setup-demo-conf](./wasmplugin/rules/crs-setup-demo.conf).

In order to monitor envoy logs while performing requests you can run:

- Envoy logs: `docker-compose -f ./example/docker-compose.yml logs -f envoy-logs`.
Expand Down
File renamed without changes.
File renamed without changes.
130 changes: 130 additions & 0 deletions example/istio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Coraza Proxy WASM as WasmPlugin for Istio

WasmPlugins allow the Istio proxy to be enhanced with WebAssembly filters.
The coraza proxy wasm acts as one of these filters, adding WAF features to Istio.
The execution order within Envoy's filter chain is set by phase and priority, facilitating
intricate interactions between user-provided WasmPlugins and Istio's built-in filters.

## Istio Setup

Given a multitude of possible Istio setups, we will only cover the most common one with the following assumptions:

- Istio is installed in the `istio-system` namespace
- The mesh has an entrypoint served by a `istio-ingressgateway` service
- Services served by Istio have an `istio-proxy` sidecar

## Getting started

The coraza proxy wasm can filter traffic inside the mesh at multiple locations.

### At Ingress gateway for all incoming traffic

The envoy pod of the ingress-gateway can be configured to use the coraza proxy wasm as a filter, thus
filtering all incoming traffic.

The following example shows how to configure embedded [Core Rule Set](https://github.com/coreruleset/coreruleset)
at the ingress gateway and use the coraza proxy wasm as a filter.

It utilizes the
[WasmPlugin](https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/) resource of Istio.
This way the filter can be configured via the `pluginConfig` field and envoy configuration is abstracted away.

```yaml
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: coraza-ingressgateway
namespace: istio-ingress
spec:
imagePullPolicy: IfNotPresent
phase: AUTHN
pluginConfig:
default_directives: default
directives_map:
default:
- Include @demo-conf
- SecDebugLogLevel 9
- SecRuleEngine On
- Include @crs-setup-demo-conf
- Include @owasp_crs/*.conf
selector:
matchLabels:
app: istio-ingressgateway
istio: ingressgateway
url: oci://ghcr.io/corazawaf/coraza-proxy-wasm
```
The `selector` needs to match labels attached to the pods of the ingress gateway.
The `url` points to the OCI image of the coraza proxy wasm, which is provided by the project.

All traffic entering the mesh via the ingress gateway will now be filtered by the coraza proxy wasm
and violations will be logged to the istio-proxy's log and a `403 Forbidden` response will be returned to the client.

### At each namespace individually

Traffic which has successfully passed the ingress gateway can be filtered at each namespace individually using
a similar approach as above.
The following example will show how to load the entire [Core Rule Set](https://github.com/coreruleset/coreruleset).

```yaml
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: coraza-core-rule-set
namespace: my-app
spec:
imagePullPolicy: IfNotPresent
phase: AUTHN
pluginConfig:
default_directives: default
directives_map:
default:
- Include @demo-conf
- SecDebugLogLevel 9
- SecRuleEngine On
- Include @crs-setup-demo-conf
- Include @owasp_crs/*.conf
selector:
matchLabels:
app: my-app
url: oci://ghcr.io/corazawaf/coraza-proxy-wasm
```

The `selector` needs to match labels attached to the pods of the namespace where filtering is desired.
The `namespace` field needs to match the namespace of the pods.

All traffic entering the namespace will now be filtered by the coraza proxy wasm using the
entire [Core Rule Set](https://github.com/coreruleset/coreruleset) and
violations will be logged to the istio-proxy's log and a `403 Forbidden` response will be returned to the client.

Traffic which has already been filtered by the ingress gateway will not reach the namespace and will only be
logged to the istio-proxy's log in the namespace of the ingress-gateway.

## Testing and Logs

The coraza proxy wasm logs violations to the istio-proxy's log.

The following example shows a violation to the rule `REQUEST-941-APPLICATION-ATTACK-XSS` which is included in the
istio-ingressgateways filter configuration.

```bash
curl 'https://my-app.my-domain.com/anything?arg=<script>alert(0)</script>' -IL
HTTP/2 403
vary: Accept-Encoding
date: Tue, 10 Oct 2023 13:45:47 GMT
server: istio-envoy
```

Depending on your configuration a log in the istio-proxy's log will look like this:

```text
envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1157
wasm log istio-ingress.coraza-ingressgateway: [client "my-client"]
Coraza: Warning. Javascript method detected [file "@owasp_crs/REQUEST-941-APPLICATION-ATTACK-XSS.conf"]
[line "7982"] [id "941390"] [rev ""] [msg "Javascript method detected"]
[data "Matched Data: alert( found within ARGS_GET:arg: <script>alert(0)</script>"]
[severity "critical"] [ver "OWASP_CRS/4.0.0-rc1"] [maturity "0"] [accuracy "0"]
[tag "application-multi"] [tag "language-multi"] [tag "attack-xss"] [tag "paranoia-level/1"]
[tag "OWASP_CRS"] [tag "capec/1000/152/242"] [hostname "my-hostname"] [uri "/anything/?arg=<script>alert(0)</script>"]
[unique_id "wTueIQloYpvpWNLzVfy"] thread=27
```
18 changes: 9 additions & 9 deletions magefiles/magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,19 +272,19 @@ func Ftw() error {
return sh.RunWithV(env, "docker-compose", "--file", "ftw/docker-compose.yml", "run", "--rm", task)
}

// RunExample spins up the test environment, access at http://localhost:8080. Requires docker-compose.
func RunExample() error {
return sh.RunWithV(map[string]string{"ENVOY_IMAGE": os.Getenv("ENVOY_IMAGE")}, "docker-compose", "--file", "example/docker-compose.yml", "up", "-d", "envoy-logs")
// RunEnvoyExample spins up the test environment of envoy, access at http://localhost:8080. Requires docker-compose.
func RunEnvoyExample() error {
return sh.RunWithV(map[string]string{"ENVOY_IMAGE": os.Getenv("ENVOY_IMAGE")}, "docker-compose", "--file", "example/envoy/docker-compose.yml", "up", "-d", "envoy-logs")
}

// TeardownExample tears down the test environment. Requires docker-compose.
func TeardownExample() error {
return sh.RunV("docker-compose", "--file", "example/docker-compose.yml", "down")
// TeardownEnvoyExample tears down the test environment of envoy. Requires docker-compose.
func TeardownEnvoyExample() error {
return sh.RunV("docker-compose", "--file", "example/envoy/docker-compose.yml", "down")
}

// ReloadExample reload the test environment (container) in case of envoy or wasm update. Requires docker-compose
func ReloadExample() error {
return sh.RunV("docker-compose", "--file", "example/docker-compose.yml", "restart")
// ReloadEnvoyExample reload the test environment (container) of envoy in case of envoy or wasm update. Requires docker-compose
func ReloadEnvoyExample() error {
return sh.RunV("docker-compose", "--file", "example/envoy/docker-compose.yml", "restart")
}

var Default = Build
Expand Down

0 comments on commit 02eda47

Please sign in to comment.