diff --git a/README.md b/README.md index a1b487f..dd63c12 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,10 @@ Targets: ``` ### Building requirements + Building the filter requires: -- [Go](https://go.dev/doc/install) + +- [Go](https://go.dev/doc/install) - [TinyGo](https://tinygo.org/getting-started/install/) Up to date required versions can be found looking at [`minGoVersion` and `tinygoMinorVersion` variables](./magefiles/magefile.go). @@ -163,10 +165,12 @@ 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 [@recommended-conf](./wasmplugin/rules/coraza.conf-recommended.conf) and [@crs-setup-conf](./wasmplugin/rules/crs-setup.conf.example). -In order to monitor envoy logs while performing requests you can run: +In order to individually monitor envoy logs while performing requests, in another terminal you can run: + +- Envoy logs: `docker-compose -f ./example/envoy/docker-compose.yml logs -f envoy-logs`. +- Critical wasm (audit) logs: `docker-compose -f ./example/envoy/docker-compose.yml logs -f wasm-logs` -- Envoy logs: `docker-compose -f ./example/docker-compose.yml logs -f envoy-logs`. -- Critical wasm (audit) logs: `docker-compose -f ./example/docker-compose.yml logs -f wasm-logs` +The Envoy example comes also with a Grafana dashboard that can be accessed at `localhost:3000` (admin/admin) in order to monitor the memory consumption. ### Manual requests diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 3e3f278..fd4379c 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -15,6 +15,10 @@ services: command: - -c - /conf/envoy-config.yaml + - --service-cluster # required to export metrics + - envoy + - --service-node # required to export metrics + - envoy volumes: - ../build:/build - .:/conf diff --git a/example/envoy/docker-compose.yml b/example/envoy/docker-compose.yml index 676435e..a5bcd74 100644 --- a/example/envoy/docker-compose.yml +++ b/example/envoy/docker-compose.yml @@ -30,13 +30,17 @@ services: - --log-format [%Y-%m-%d %T.%f][%t][%l][%n] [%g:%#] %v - --log-path - /home/envoy/logs/envoy.log + - --service-cluster # required to export metrics + - envoy + - --service-node # required to export metrics + - envoy volumes: - ../../build:/build - .:/conf - logs:/home/envoy/logs:rw ports: - 8080:8080 - - 8082:8082 + - 8082:8082 # admin port (also for metrics) envoy-logs: depends_on: @@ -61,5 +65,23 @@ services: volumes: - logs:/home/envoy/logs:ro + prometheus: + image: prom/prometheus + volumes: + - ./prometheus.yaml:/etc/prometheus.yaml + ports: + - "9090:9090" + command: "--config.file=/etc/prometheus.yaml" + + grafana: + image: grafana/grafana + volumes: + - ./grafana/grafana.ini:/etc/grafana/grafana.ini + - ./grafana/datasource.yaml:/etc/grafana/provisioning/datasources/datasource.yaml + - ./grafana/dashboard.yaml:/etc/grafana/provisioning/dashboards/dashboard.yaml + - ./grafana/dashboard.json:/etc/grafana/provisioning/dashboards/dashboard.json + ports: + - "3000:3000" + volumes: logs: diff --git a/example/envoy/envoy-config.yaml b/example/envoy/envoy-config.yaml index b56884b..7156691 100644 --- a/example/envoy/envoy-config.yaml +++ b/example/envoy/envoy-config.yaml @@ -30,7 +30,7 @@ static_resources: # A custom response header is added for e2e testing purposes. A local response, triggered by an interruption, # has to allow custom added headers like this. See https://github.com/corazawaf/coraza-proxy-wasm/pull/172 response_headers_to_add: - - header: + - header: key: "custom_header" value: "custom_value" virtual_hosts: diff --git a/example/envoy/grafana/dashboard.json b/example/envoy/grafana/dashboard.json new file mode 100644 index 0000000..d88edd8 --- /dev/null +++ b/example/envoy/grafana/dashboard.json @@ -0,0 +1,448 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": "$datasource", + "description": "Current amount of allocated memory in bytes. Total of both new and old Envoy processes on hot restart.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 11, + "links": [], + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": "$datasource", + "editorMode": "code", + "expr": "envoy_server_memory_allocated", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy", + "range": true, + "refId": "A" + } + ], + "title": "Allocated Memory", + "type": "timeseries" + }, + { + "datasource": "$datasource", + "description": "Current reserved heap size. New Envoy process heap size on hot restart.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 13, + "links": [], + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": "$datasource", + "editorMode": "code", + "expr": "envoy_server_memory_heap_size", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy", + "range": true, + "refId": "A" + } + ], + "title": "Heap Size", + "type": "timeseries" + }, + { + "datasource": "$datasource", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 14, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": "$datasource", + "editorMode": "code", + "expr": "max_over_time(envoy_server_memory_allocated[$__range])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Max Allocated Memory", + "type": "stat" + }, + { + "datasource": "$datasource", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 15, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": "$datasource", + "editorMode": "code", + "expr": "max_over_time(envoy_server_memory_heap_size[$__range])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Max Heap Size", + "type": "stat" + } + ], + "refresh": "5s", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Example dashboard", + "uid": "c5934944-4bb1-425b-b7b1-e2e4f56668a9", + "version": 2, + "weekStart": "" + } diff --git a/example/envoy/grafana/dashboard.yaml b/example/envoy/grafana/dashboard.yaml new file mode 100644 index 0000000..4c51681 --- /dev/null +++ b/example/envoy/grafana/dashboard.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: "default" + orgId: 1 + folder: "" + type: file + disableDeletion: false + editable: true + options: + path: /etc/grafana/provisioning/dashboards/ diff --git a/example/envoy/grafana/datasource.yaml b/example/envoy/grafana/datasource.yaml new file mode 100644 index 0000000..22aaf0b --- /dev/null +++ b/example/envoy/grafana/datasource.yaml @@ -0,0 +1,9 @@ +apiVersion: 1 + +datasources: + - name: prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + editable: true + isDefault: diff --git a/example/envoy/grafana/grafana.ini b/example/envoy/grafana/grafana.ini new file mode 100644 index 0000000..291273c --- /dev/null +++ b/example/envoy/grafana/grafana.ini @@ -0,0 +1,5 @@ +instance_name = "grafana" + +[security] +admin_user = admin +admin_password = admin diff --git a/example/envoy/prometheus.yaml b/example/envoy/prometheus.yaml new file mode 100644 index 0000000..3e9ec8c --- /dev/null +++ b/example/envoy/prometheus.yaml @@ -0,0 +1,10 @@ +global: + scrape_interval: 15s +scrape_configs: + - job_name: "envoy-stats" + metrics_path: /stats/prometheus + scrape_interval: 5s + static_configs: + - targets: ["envoy:8082"] + labels: + group: "services"