diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 152691459..e813c6896 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -126,6 +126,9 @@ jobs: path: kubernetes-ci secrets: | kv-gitlab-ci/data/github/ingress api_token ; + kv-gitlab-ci/data/github/ingress api_host ; + kv-gitlab-ci/data/github/ingress api_preset ; + kv-gitlab-ci/data/github/ingress client_id ; kv-gitlab-ci/data/github/ingress user_secret ; kv-gitlab-ci/data/github/ingress user_uuid ; kv-gitlab-ci/data/github/shared/smoke-tests-registry-creds token_name ; @@ -150,6 +153,9 @@ jobs: SKIP_CLUSTER_CREATION: true SKIP_IMAGE_CREATION: true WALLARM_API_TOKEN: ${{ steps.secrets.outputs.api_token }} + WALLARM_API_HOST: ${{ steps.secrets.outputs.api_host }} + WALLARM_API_PRESET: ${{ steps.secrets.outputs.api_preset }} + CLIENT_ID: ${{ steps.secrets.outputs.client_id }} USER_UUID: ${{ steps.secrets.outputs.user_uuid }} USER_SECRET: ${{ steps.secrets.outputs.user_secret }} SMOKE_REGISTRY_TOKEN: ${{ steps.secrets.outputs.token_name }} @@ -161,6 +167,7 @@ jobs: ALLURE_PROJECT_ID: ${{ secrets.ALLURE_PROJECT_ID }} ALLURE_ENVIRONMENT_K8S: ${{ matrix.k8s }} ALLURE_ENVIRONMENT_ARCH: ${{ matrix.ARCH }} + TEST_RC: true run: | make kind-smoke-test @@ -263,7 +270,7 @@ jobs: env: ARCH: amd64 strategy: - fail-fast: false # TODO: temporary for arm64 new arc testing + fail-fast: true matrix: k8s: [v1.24.12, v1.25.8, v1.26.3,v1.27.1, v1.28.0] @@ -277,7 +284,9 @@ jobs: role: ${{ secrets.VAULT_ROLE }} method: kubernetes path: kubernetes-ci - secrets: kv-gitlab-ci/data/github/ingress api_token + secrets: | + kv-gitlab-ci/data/github/ingress api_token ; + kv-gitlab-ci/data/github/ingress api_host ; - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3.0.2 @@ -301,6 +310,7 @@ jobs: SKIP_E2E_IMAGE_CREATION: true WALLARM_ENABLED: true WALLARM_API_TOKEN: ${{ steps.secrets.outputs.api_token }} + WALLARM_API_HOST: ${{ steps.secrets.outputs.api_host }} run: | kind get kubeconfig > $HOME/.kube/kind-config-kind make E2E_NODES=6 kind-e2e-test diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml index 82189f7f0..51b9a8cbc 100644 --- a/.github/workflows/helm-publish.yml +++ b/.github/workflows/helm-publish.yml @@ -47,27 +47,14 @@ jobs: echo "Release type: ${TYPE}" echo "type=${TYPE}" >> $GITHUB_OUTPUT - - name: Publish Helm charts (Prod) - if: steps.check_release.outputs.type == 'production' - uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # master - with: - token: ${{ steps.secrets.outputs.GITHUB_TOKEN }} - charts_dir: ./charts - charts_url: https://charts.wallarm.com - linting: off - repository: helm-charts - branch: main - target_dir: "wallarm-ingress" - index_dir: . - app_version: "${{ env.X_TAG }}" - chart_version: "${{ env.X_TAG }}" - - - name: Update chart name for RC versions + - name: Update versions for RC if: steps.check_release.outputs.type == 'release-candidate' - run: yq -y -i '.name = "wallarm-ingress-rc"' ./charts/ingress-nginx/Chart.yaml + run: | + yq -y -i '.version += "-rc"' ./charts/ingress-nginx/Chart.yaml + echo "X_TAG=${X_TAG}-rc" >> $GITHUB_ENV - - name: Publish Helm charts (RC) - if: steps.check_release.outputs.type == 'release-candidate' + - name: Publish Helm charts + if: steps.check_release.outputs.type =~ 'production|release-candidate' uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # master with: token: ${{ steps.secrets.outputs.GITHUB_TOKEN }} @@ -76,7 +63,7 @@ jobs: linting: off repository: helm-charts branch: main - target_dir: "wallarm-ingress-rc" + target_dir: "wallarm-ingress" index_dir: . app_version: "${{ env.X_TAG }}" chart_version: "${{ env.X_TAG }}" diff --git a/.github/workflows/smoke-test.yaml b/.github/workflows/smoke-test.yaml index f9861cb01..56a094804 100644 --- a/.github/workflows/smoke-test.yaml +++ b/.github/workflows/smoke-test.yaml @@ -34,9 +34,9 @@ jobs: method: kubernetes path: kubernetes-ci secrets: | - kv-gitlab-ci/data/github/ingress api_token ; - kv-gitlab-ci/data/github/ingress user_secret ; - kv-gitlab-ci/data/github/ingress user_uuid ; + kv-gitlab-ci/data/github/ingress-audit api_token ; + kv-gitlab-ci/data/github/ingress-audit user_secret ; + kv-gitlab-ci/data/github/ingress-audit user_uuid ; kv-gitlab-ci/data/github/shared/smoke-tests-registry-creds token_name ; kv-gitlab-ci/data/github/shared/smoke-tests-registry-creds token_secret ; @@ -59,12 +59,16 @@ jobs: ALLURE_ENDPOINT: ${{ secrets.ALLURE_SERVER_URL }} ALLURE_PROJECT_ID: ${{ secrets.ALLURE_PROJECT_ID }} WALLARM_API_TOKEN: ${{ steps.secrets.outputs.api_token }} + WALLARM_API_HOST: audit.api.wallarm.com # TODO: tmp + WALLARM_API_PRESET: audit # TODO: tmp + CLIENT_ID: "55146" # TODO: tmp USER_UUID: ${{ steps.secrets.outputs.user_uuid }} USER_SECRET: ${{ steps.secrets.outputs.user_secret }} SMOKE_REGISTRY_TOKEN: ${{ steps.secrets.outputs.token_name }} SMOKE_REGISTRY_SECRET: ${{ steps.secrets.outputs.token_secret }} ALLURE_ENVIRONMENT_K8S: ${{ matrix.k8s }} ALLURE_ENVIRONMENT_ARCH: amd64 + TEST_RC: true run: | if [ ${{ github.event_name }} == 'workflow_dispatch' ]; then diff --git a/AIO_BASE b/AIO_BASE index 6ca6df113..2e2e24f71 100644 --- a/AIO_BASE +++ b/AIO_BASE @@ -1 +1 @@ -4.8.0 \ No newline at end of file +4.10.0-rc3 \ No newline at end of file diff --git a/TAG b/TAG index 856d23452..6829932d3 100644 --- a/TAG +++ b/TAG @@ -1 +1 @@ -4.8.1-1 +4.10.0-1 diff --git a/charts/ingress-nginx/Chart.yaml b/charts/ingress-nginx/Chart.yaml index afc34e476..d3c163ca9 100644 --- a/charts/ingress-nginx/Chart.yaml +++ b/charts/ingress-nginx/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: wallarm-ingress -version: 4.8.5 -appVersion: 4.8.1-1 +version: 4.10.0 +appVersion: 4.10.0-1 home: https://github.com/wallarm/ingress description: Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer with Wallarm module icon: https://static.wallarm.com/wallarm-logo.svg diff --git a/charts/ingress-nginx/templates/_helpers.tpl b/charts/ingress-nginx/templates/_helpers.tpl index a314a59c1..8f3586669 100644 --- a/charts/ingress-nginx/templates/_helpers.tpl +++ b/charts/ingress-nginx/templates/_helpers.tpl @@ -89,6 +89,14 @@ Get specific paths {{- end }} {{- end -}} +{{- define "wallarm-apifw.path" -}} +{{- if .Values.controller.image.chroot -}} +{{- printf "/chroot/opt/wallarm/var/lib/wallarm-api" -}} +{{- else -}} +{{- printf "/opt/wallarm/var/lib/wallarm-api" -}} +{{- end }} +{{- end -}} + {{/* Get specific image */}} @@ -246,6 +254,8 @@ Create the name of the controller service account to use name: wallarm - mountPath: {{ include "wallarm-acl.path" . }} name: wallarm-acl + - mountPath: {{ include "wallarm-apifw.path" . }} + name: wallarm-apifw - mountPath: /secrets/wallarm/token name: wallarm-token subPath: token @@ -279,6 +289,8 @@ Create the name of the controller service account to use name: wallarm - mountPath: {{ include "wallarm-acl.path" . }} name: wallarm-acl + - mountPath: {{ include "wallarm-apifw.path" . }} + name: wallarm-apifw - mountPath: /opt/cron/crontab name: wallarm-cron subPath: crontab @@ -320,6 +332,51 @@ Create the name of the controller service account to use {{ toYaml .Values.controller.wallarm.collectd.resources | indent 4 }} {{- end -}} +{{- define "ingress-nginx.wallarmApifirewallContainer" -}} +- name: api-firewall +{{- if .Values.controller.wallarm.apifirewall.image }} + {{- with .Values.controller.wallarm.apifirewall.image }} + image: "{{ .repository }}:{{ .tag }}" + {{- end }} +{{- else }} + image: "{{ .Values.controller.wallarm.helpers.image }}:{{ .Values.controller.wallarm.helpers.tag }}" +{{- end }} + imagePullPolicy: "{{ .Values.controller.image.pullPolicy }}" + args: ["api-firewall"] + env: + - name: APIFW_SPECIFICATION_UPDATE_PERIOD + value: "{{ .Values.controller.wallarm.apifirewall.config.specificationUpdatePeriod }}" + - name: API_MODE_UNKNOWN_PARAMETERS_DETECTION + value: "{{ .Values.controller.wallarm.apifirewall.config.unknownParametersDetection }}" + - name: APIFW_URL + value: "http://0.0.0.0:{{ .Values.controller.wallarm.apifirewall.config.mainPort }}" + - name: APIFW_HEALTH_HOST + value: "0.0.0.0:{{ .Values.controller.wallarm.apifirewall.config.healthPort }}" + - name: APIFW_LOG_LEVEL + value: "{{ .Values.controller.wallarm.apifirewall.config.logLevel }}" + - name: APIFW_LOG_FORMAT + value: "{{ .Values.controller.wallarm.apifirewall.config.logFormat }}" + - name: APIFW_MODE + value: api + - name: APIFW_READ_TIMEOUT + value: 5s + - name: APIFW_WRITE_TIMEOUT + value: 5s + - name: APIFW_API_MODE_DEBUG_PATH_DB + value: "/opt/wallarm/var/lib/wallarm-api/1/wallarm_api.db" + volumeMounts: + - name: wallarm-apifw + mountPath: {{ include "wallarm-apifw.path" . }} + securityContext: {{ include "controller.containerSecurityContext" . | nindent 4 }} + resources: {{ toYaml .Values.controller.wallarm.apifirewall.resources | nindent 4 }} +{{- if .Values.controller.wallarm.apifirewall.livenessProbeEnabled }} + livenessProbe: {{ toYaml .Values.controller.wallarm.apifirewall.livenessProbe | nindent 4 }} +{{- end }} +{{- if .Values.controller.wallarm.apifirewall.readinessProbeEnabled }} + readinessProbe: {{ toYaml .Values.controller.wallarm.apifirewall.readinessProbe | nindent 4 }} +{{- end }} +{{- end -}} + {{/* Create the name of the backend service account to use - only used when podsecuritypolicy is also enabled */}} diff --git a/charts/ingress-nginx/templates/controller-configmap-cron.yaml b/charts/ingress-nginx/templates/controller-configmap-cron.yaml index 114830421..ffad77951 100644 --- a/charts/ingress-nginx/templates/controller-configmap-cron.yaml +++ b/charts/ingress-nginx/templates/controller-configmap-cron.yaml @@ -13,25 +13,32 @@ data: crontab: | {{- with .Values.controller.wallarm.cron.jobs.exportEnvironment }} # export-environment - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-environment -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-environment -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.syncIpLists }} # sync-ip-lists - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-ip-lists -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-ip-lists -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.exportMetrics }} # export-metrics - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-metrics -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-metrics -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.syncIpListsSource }} # sync-ip-lists-source - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-ip-lists-source -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-ip-lists-source -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.syncNode }} # sync-node - {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/syncnode -f -p -r 120 -l STDOUT -L DEBUG + {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/syncnode -f -p -r 120 -l STDOUT -L {{ .logLevel }} + {{- end }} + + {{- if .Values.controller.wallarm.apifirewall.enabled }} + {{- with .Values.controller.wallarm.cron.jobs.syncApiSpecs }} + # sync-api-specs + {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/sync-api-specs -l STDOUT -L {{ .logLevel }} + {{- end }} {{- end }} diff --git a/charts/ingress-nginx/templates/controller-configmap.yaml b/charts/ingress-nginx/templates/controller-configmap.yaml index f7170f5eb..2e5cf9ab6 100644 --- a/charts/ingress-nginx/templates/controller-configmap.yaml +++ b/charts/ingress-nginx/templates/controller-configmap.yaml @@ -18,6 +18,8 @@ data: enable-wallarm: "{{ .Values.controller.wallarm.enabled }}" wallarm-upstream-service: "{{ include "ingress-nginx.controller.fullname" . }}-wallarm-tarantool" wallarm-metrics-port: "{{ .Values.controller.wallarm.metrics.port }}" + wallarm-apifw-enabled: "{{ .Values.controller.wallarm.apifirewall.enabled }}" + wallarm-apifw-port: "{{ .Values.controller.wallarm.apifirewall.config.mainPort }}" {{- if .Values.controller.wallarm.fallback }} wallarm-fallback: "{{ .Values.controller.wallarm.fallback }}" {{- end }} diff --git a/charts/ingress-nginx/templates/controller-daemonset.yaml b/charts/ingress-nginx/templates/controller-daemonset.yaml index e1c1437b5..c70c5f52a 100644 --- a/charts/ingress-nginx/templates/controller-daemonset.yaml +++ b/charts/ingress-nginx/templates/controller-daemonset.yaml @@ -31,6 +31,7 @@ spec: annotations: {{- if and .Values.controller.wallarm.enabled (not .Values.controller.wallarm.existingSecret.enabled) }} checksum/token: {{ .Values.controller.wallarm.token | sha256sum }} + checksum/cron: {{ .Values.controller.wallarm.cron.jobs | toJson | sha256sum }} {{- end }} {{- if .Values.controller.podAnnotations -}} {{- range $key, $value := .Values.controller.podAnnotations }} @@ -198,6 +199,9 @@ spec: {{- if .Values.controller.wallarm.enabled }} {{ include "ingress-nginx.wallarmCronContainer" . | nindent 8 }} {{ include "ingress-nginx.wallarmCollectdContainer" . | nindent 8 }} + {{- if .Values.controller.wallarm.apifirewall.enabled }} + {{ include "ingress-nginx.wallarmApifirewallContainer" . | nindent 8 }} + {{- end }} {{- end }} {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules .Values.controller.opentelemetry.enabled .Values.controller.wallarm.enabled) }} initContainers: @@ -249,6 +253,8 @@ spec: emptyDir: {} - name: wallarm-cache emptyDir: {} + - name: wallarm-apifw + emptyDir: {} - name: wallarm-cron configMap: name: {{ template "ingress-nginx.wallarmControllerCronConfig" . }} diff --git a/charts/ingress-nginx/templates/controller-deployment.yaml b/charts/ingress-nginx/templates/controller-deployment.yaml index fe7d5711d..5b5feb7b8 100644 --- a/charts/ingress-nginx/templates/controller-deployment.yaml +++ b/charts/ingress-nginx/templates/controller-deployment.yaml @@ -34,6 +34,7 @@ spec: annotations: {{- if and .Values.controller.wallarm.enabled (not .Values.controller.wallarm.existingSecret.enabled) }} checksum/token: {{ .Values.controller.wallarm.token | sha256sum }} + checksum/cron: {{ .Values.controller.wallarm.cron.jobs | toJson | sha256sum }} {{- end }} {{- if .Values.controller.podAnnotations -}} {{- range $key, $value := .Values.controller.podAnnotations }} @@ -201,6 +202,9 @@ spec: {{- if .Values.controller.wallarm.enabled }} {{ include "ingress-nginx.wallarmCronContainer" . | nindent 8 }} {{ include "ingress-nginx.wallarmCollectdContainer" . | nindent 8 }} + {{- if .Values.controller.wallarm.apifirewall.enabled }} + {{ include "ingress-nginx.wallarmApifirewallContainer" . | nindent 8 }} + {{- end }} {{- end }} {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules .Values.controller.opentelemetry.enabled .Values.controller.wallarm.enabled) }} initContainers: @@ -252,6 +256,8 @@ spec: emptyDir: {} - name: wallarm-cache emptyDir: {} + - name: wallarm-apifw + emptyDir: {} - name: wallarm-cron configMap: name: {{ template "ingress-nginx.wallarmControllerCronConfig" . }} diff --git a/charts/ingress-nginx/templates/tarantool-configmap.yaml b/charts/ingress-nginx/templates/tarantool-configmap.yaml index 4b8a2b782..0ec8aeb9c 100644 --- a/charts/ingress-nginx/templates/tarantool-configmap.yaml +++ b/charts/ingress-nginx/templates/tarantool-configmap.yaml @@ -13,40 +13,45 @@ data: crontab: | {{- with .Values.controller.wallarm.cron.jobs.exportAttacks }} # export-attacks - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-attacks -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-attacks -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.exportCounters }} # export-counters - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-counters -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-counters -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.exportEnvironment }} # export-environment - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-environment -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-environment -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.bruteDetect }} # brute-detect - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/brute-detect -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/brute-detect -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.syncMarkers }} # sync-markers - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-markers -l STDOUT + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/sync-markers -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.weakJwtDetect }} # weak-jwt-detect - {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/weak-jwt-detect -l STDOUT + {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/weak-jwt-detect -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.syncNode }} # sync-node - {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/syncnode -f -p -r 120 -l STDOUT -L DEBUG + {{ .schedule }} /opt/wallarm/usr/share/wallarm-common/syncnode -f -p -r 120 -l STDOUT -L {{ .logLevel }} {{- end }} {{- with .Values.controller.wallarm.cron.jobs.exportBlockedStat }} # export-blocked-stats - {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-blocked-stats -l STDOUT -L DEBUG - {{- end }} \ No newline at end of file + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/export-blocked-stats -l STDOUT -L {{ .logLevel }} + {{- end }} + + {{- with .Values.controller.wallarm.cron.jobs.detectCredStuffing }} + # detect-cred-stuffing + {{ .schedule }} timeout {{ .timeout }} /opt/wallarm/usr/share/wallarm-common/detect-cred-stuffing -l STDOUT -L {{ .logLevel }} + {{- end }} diff --git a/charts/ingress-nginx/templates/tarantool-daemonset.yaml b/charts/ingress-nginx/templates/tarantool-daemonset.yaml index a1ebc7f40..36289c195 100644 --- a/charts/ingress-nginx/templates/tarantool-daemonset.yaml +++ b/charts/ingress-nginx/templates/tarantool-daemonset.yaml @@ -26,6 +26,7 @@ spec: {{- if not .Values.controller.wallarm.existingSecret.enabled }} annotations: checksum/token: {{ .Values.controller.wallarm.token | sha256sum }} + checksum/cron: {{ .Values.controller.wallarm.cron.jobs | toJson | sha256sum }} {{- end }} labels: {{- include "ingress-nginx.selectorLabels" . | nindent 8 }} @@ -119,6 +120,8 @@ spec: emptyDir: {} - name: wallarm-acl emptyDir: {} + - name: wallarm-apifw + emptyDir: {} - name: wallarm-cron configMap: name: {{ template "ingress-nginx.wallarmTarantoolCronConfig" . }} diff --git a/charts/ingress-nginx/templates/tarantool-deployment.yaml b/charts/ingress-nginx/templates/tarantool-deployment.yaml index f7e2a6785..2d6d77336 100644 --- a/charts/ingress-nginx/templates/tarantool-deployment.yaml +++ b/charts/ingress-nginx/templates/tarantool-deployment.yaml @@ -27,6 +27,7 @@ spec: {{- if not .Values.controller.wallarm.existingSecret.enabled }} annotations: checksum/token: {{ .Values.controller.wallarm.token | sha256sum }} + checksum/cron: {{ .Values.controller.wallarm.cron.jobs | toJson | sha256sum }} {{- end }} labels: {{- include "ingress-nginx.selectorLabels" . | nindent 8 }} @@ -120,6 +121,8 @@ spec: emptyDir: {} - name: wallarm-acl emptyDir: {} + - name: wallarm-apifw + emptyDir: {} - name: wallarm-cron configMap: name: {{ template "ingress-nginx.wallarmTarantoolCronConfig" . }} diff --git a/charts/ingress-nginx/values.yaml b/charts/ingress-nginx/values.yaml index 5de82a8df..dbe24e058 100644 --- a/charts/ingress-nginx/values.yaml +++ b/charts/ingress-nginx/values.yaml @@ -27,7 +27,7 @@ controller: ## for backwards compatibility consider setting the full image url via the repository value below ## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail ## repository: - tag: "4.8.1-1" + tag: "4.10.0-1" pullPolicy: IfNotPresent # www-data -> uid 101 runAsUser: 101 @@ -790,7 +790,7 @@ controller: ## The image name and tag for the helper image ## image: docker.io/wallarm/node-helpers - tag: 4.8.1 + tag: 4.10.0-rc2 tarantool: kind: Deployment service: @@ -844,39 +844,94 @@ controller: cron: jobs: exportEnvironment: + logLevel: INFO schedule: "0 */1 * * *" timeout: 10m exportAttacks: + logLevel: INFO schedule: "* * * * *" timeout: 3h exportCounters: + logLevel: ERROR schedule: "* * * * *" timeout: 11m bruteDetect: + logLevel: INFO schedule: "* * * * *" timeout: 6m syncIpLists: + logLevel: INFO schedule: "* * * * *" timeout: 3h exportMetrics: + logLevel: INFO schedule: "* * * * *" timeout: 3h syncIpListsSource: + logLevel: INFO schedule: "*/5 * * * *" timeout: 3h syncMarkers: + logLevel: INFO schedule: "* * * * *" timeout: 1h syncNode: + logLevel: INFO schedule: "*/2 * * * *" weakJwtDetect: + logLevel: INFO schedule: "* * * * *" exportBlockedStat: + logLevel: INFO schedule: "* * * * *" timeout: 24h + detectCredStuffing: + logLevel: INFO + schedule: "* * * * *" + timeout: 10m + syncApiSpecs: + logLevel: INFO + schedule: "* * * * *" + timeout: 10m resources: {} collectd: resources: {} + apifirewall: + ### Enable or disable API Firewall functionality (true|false) + ### + enabled: true + config: + mainPort: 18081 + healthPort: 18082 + specificationUpdatePeriod: 1m + unknownParametersDetection: true + #### TRACE|DEBUG|INFO|WARNING|ERROR + logLevel: DEBUG + ### TEXT|JSON + logFormat: TEXT + resources: {} + livenessProbeEnabled: false + livenessProbe: + httpGet: + path: "/v1/liveness" + port: 18082 + scheme: HTTP + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbeEnabled: false + readinessProbe: + httpGet: + path: "/v1/readiness" + port: 18082 + scheme: HTTP + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 # -- Rollback limit ## diff --git a/go.work.sum b/go.work.sum index b90672997..572fb7605 100644 --- a/go.work.sum +++ b/go.work.sum @@ -122,6 +122,8 @@ cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2t cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= @@ -154,6 +156,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -199,6 +202,7 @@ github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3 github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -206,9 +210,13 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= +go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq9BgzFU6s= +go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= go.etcd.io/etcd/pkg/v3 v3.5.7/go.mod h1:kcOfWt3Ov9zgYdOiJ/o1Y9zFfLhQjylTgL4Lru8opRo= go.etcd.io/etcd/raft/v3 v3.5.7/go.mod h1:TflkAb/8Uy6JFBxcRaH2Fr6Slm9mCPVdI2efzxY96yU= go.etcd.io/etcd/server/v3 v3.5.7/go.mod h1:gxBgT84issUVBRpZ3XkW1T55NjOb4vZZRI4wVvNhf4A= @@ -302,6 +310,7 @@ gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.27.6/go.mod h1:9YQuCFa+n88RWokHkl+4RHFQ9DATSip/ihBqxlDUBuw= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= diff --git a/internal/ingress/controller/config/config.go b/internal/ingress/controller/config/config.go index 74bb6f24f..738688295 100644 --- a/internal/ingress/controller/config/config.go +++ b/internal/ingress/controller/config/config.go @@ -826,6 +826,8 @@ type Configuration struct { // https://docs.wallarm.com/en/admin-en/configure-parameters-en.html#wallarmfallback WallarmFallback string `json:"wallarm-fallback"` + WallarmAPIFwEnabled bool `json:"wallarm-apifw-enabled"` + WallarmAPIFwPort int `json:"wallarm-apifw-port"` WallarmACLExportEnable string `json:"wallarm-acl-export-enable"` WallarmACLExportShmSize string `json:"wallarm-acl-export-shm-size"` WallarmACLExportSampleLimit int `json:"wallarm-acl-export-sample-limit"` diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go index e987520c3..d14ebb261 100644 --- a/internal/ingress/controller/template/template.go +++ b/internal/ingress/controller/template/template.go @@ -290,6 +290,7 @@ var funcMap = text_template.FuncMap{ "replace": func(old, new, src string) string { //nolint:predeclared // new is okay here return strings.ReplaceAll(src, old, new) }, + "shouldEnableWallarmAPIFW": shouldEnableWallarmAPIFW, } // escapeLiteralDollar will replace the $ character with ${literal_dollar} @@ -1869,3 +1870,38 @@ func buildCorsOriginRegex(corsOrigins []string) string { originsRegex += ")$ ) { set $cors 'true'; }" return originsRegex } + +func shouldEnableWallarmAPIFW(s interface{}) bool { + server, ok := s.(*ingress.Server) + if !ok { + klog.Errorf("expected an '*ingress.Server' type but %T was returned", s) + return false + } + // Check server locations. + // If wallarm is enabled for any server location with backend proto that is + // unsupported by Wallarm APIFW, disable Wallarm APIFW for that server + wallarmIsUsedSomewhere := false + for _, location := range server.Locations { + // do not count locations with wallarm disabled + if location.Wallarm.Mode == "off" { + continue + } else { + wallarmIsUsedSomewhere = true + } + switch strings.ToUpper(location.BackendProtocol) { + case autoHTTPProtocol: + continue + case httpProtocol: + continue + case httpsProtocol: + continue + case grpcProtocol: + return false + case grpcsProtocol: + return false + case fcgiProtocol: + return false + } + } + return wallarmIsUsedSomewhere +} diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 7d2a22610..181f831ef 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -703,6 +703,27 @@ http { } {{ end }} + {{ if ($all.Cfg.EnableWallarm) }} + {{ if and ($all.Cfg.WallarmAPIFwEnabled) (shouldEnableWallarmAPIFW $server) }} + # Wallarm API Firewall + location ~ ^/wallarm-apifw(.*)$ { + wallarm_mode off; + access_log off; + proxy_pass http://127.0.0.2:{{ $all.Cfg.WallarmAPIFwPort }}$1; + error_page 404 431 = @wallarm-apifw-fallback; + error_page 500 502 503 504 = @wallarm-apifw-fallback; + } + + location @wallarm-apifw-fallback { + wallarm_mode off; + access_log off; + return 500 "API FW fallback"; + } + {{ else }} + wallarm_enable_apifw off; + {{ end }} + {{ end }} + {{ template "SERVER" serverConfig $all $server }} {{ if not (empty $cfg.ServerSnippet) }} @@ -739,6 +760,7 @@ http { keepalive_timeout 0; gzip off; + wallarm_mode off; access_log off; {{ if $cfg.EnableOpentracing }} @@ -759,6 +781,11 @@ http { modsecurity off; {{ end }} + # Ensure that Wallarm will not run on an internal location as this is not accessible from outside + {{ if $cfg.EnableWallarm }} + wallarm_mode off; + {{ end }} + listen 127.0.0.1:{{ .StatusPort }}; set $proxy_upstream_name "internal"; diff --git a/test/e2e/run-chart-test.sh b/test/e2e/run-chart-test.sh index dd03bf4fc..92ab42866 100755 --- a/test/e2e/run-chart-test.sh +++ b/test/e2e/run-chart-test.sh @@ -50,7 +50,7 @@ export ARCH=${ARCH:-amd64} # Uses a custom chart-testing image to avoid timeouts waiting for namespace deletion. CT_IMAGE="quay.io/dmitriev/chart-testing:3.7.1" -HELM_EXTRA_ARGS="--timeout 180s" +HELM_EXTRA_ARGS="--timeout 240s" HELM_EXTRA_SET_ARGS="\ --set controller.wallarm.token=${WALLARM_API_TOKEN} \ --set controller.wallarm.enabled=true \ diff --git a/test/e2e/run-e2e-suite.sh b/test/e2e/run-e2e-suite.sh index aaa2dc7fd..4b1b6f5ad 100755 --- a/test/e2e/run-e2e-suite.sh +++ b/test/e2e/run-e2e-suite.sh @@ -83,6 +83,7 @@ kubectl run --rm \ --env="NGINX_BASE_IMAGE=${NGINX_BASE_IMAGE}" \ --env="WALLARM_ENABLED=${WALLARM_ENABLED:-false}" \ --env="WALLARM_API_TOKEN=${WALLARM_API_TOKEN:-}" \ + --env="WALLARM_API_HOST=${WALLARM_API_HOST:-}" \ --env="HTTPBUN_IMAGE=${HTTPBUN_IMAGE}" \ --overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "ingress-nginx-e2e"}}' \ e2e --image=nginx-ingress-controller:e2e diff --git a/test/e2e/run-kind-e2e.sh b/test/e2e/run-kind-e2e.sh index 0502455d3..c628b3e48 100755 --- a/test/e2e/run-kind-e2e.sh +++ b/test/e2e/run-kind-e2e.sh @@ -55,6 +55,7 @@ export DOCKER_CLI_EXPERIMENTAL=enabled export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}" export WALLARM_ENABLED="${WALLARM_ENABLED:-false}" export WALLARM_API_TOKEN="${WALLARM_API_TOKEN:-}" +export WALLARM_API_HOST="${WALLARM_API_HOST:-}" SKIP_INGRESS_IMAGE_CREATION="${SKIP_INGRESS_IMAGE_CREATION:-false}" SKIP_E2E_IMAGE_CREATION="${SKIP_E2E_IMAGE_CREATION:=false}" SKIP_CLUSTER_CREATION="${SKIP_CLUSTER_CREATION:-false}" @@ -129,6 +130,10 @@ if [ "${WALLARM_ENABLED}" == "true" ]; then echo "WALLARM_API_TOKEN must be set! Exiting ..." exit 1 fi + if [ -z "${WALLARM_API_HOST}" ]; then + echo "WALLARM_API_HOST must be set! Exiting ..." + exit 1 + fi fi echo "[dev-env] running e2e tests..." diff --git a/test/e2e/wait-for-nginx.sh b/test/e2e/wait-for-nginx.sh index e984010c5..7318e8c3e 100755 --- a/test/e2e/wait-for-nginx.sh +++ b/test/e2e/wait-for-nginx.sh @@ -67,6 +67,7 @@ if [[ ! -z "$NAMESPACE_OVERLAY" && -d "$DIR/namespace-overlays/$NAMESPACE_OVERLA --set controller.image.chroot="${IS_CHROOT}" \ --set controller.wallarm.enabled="${WALLARM_ENABLED}" \ --set controller.wallarm.token="${WALLARM_API_TOKEN}" \ + --set controller.wallarm.apiHost="${WALLARM_API_HOST}" \ --set controller.wallarm.fallback="off" else cat << EOF | helm install nginx-ingress ${DIR}/charts/ingress-nginx --namespace=$NAMESPACE --values - @@ -77,6 +78,7 @@ controller: wallarm: enabled: ${WALLARM_ENABLED} token: ${WALLARM_API_TOKEN} + apiHost: ${WALLARM_API_HOST} fallback: "off" image: repository: wallarm/ingress-controller diff --git a/test/smoke/run-smoke-suite.sh b/test/smoke/run-smoke-suite.sh index d93246538..efaaa11b4 100755 --- a/test/smoke/run-smoke-suite.sh +++ b/test/smoke/run-smoke-suite.sh @@ -48,6 +48,8 @@ function get_logs() { kubectl logs -l "app.kubernetes.io/component=controller" -c controller --tail=-1 echo "###### Cron container logs ######" kubectl logs -l "app.kubernetes.io/component=controller" -c cron --tail=-1 + echo "###### API-WF container logs ######" + kubectl logs -l "app.kubernetes.io/component=controller" -c api-firewall --tail=-1 || true echo "###### List directory /opt/wallarm/etc/wallarm" kubectl exec "${POD}" -c controller -- sh -c "ls -laht /opt/wallarm/etc/wallarm && cat /opt/wallarm/etc/wallarm/node.yaml" || true echo "###### List directory /var/lib/nginx/wallarm" @@ -132,6 +134,7 @@ spec: - {name: ALLURE_PROJECT_ID, value: "${ALLURE_PROJECT_ID:-}"} - {name: ALLURE_TOKEN, value: "${ALLURE_TOKEN:-}"} - {name: ALLURE_RESULTS, value: "${ALLURE_RESULTS:-/tests/_out/allure_report}"} + - {name: TEST_RC, value: "${TEST_RC:-false}"} - name: ALLURE_LAUNCH_TAGS value: > USER:${GITHUB_ACTOR:-local},