Integrate Wallarm

Wallarm WAF integration overview

The Kosmos UI provides the ability to install the Wallarm WAF ingress controller, which is an nginx-based ingress controller with security-rich features provided by Wallarm WAF functionality.

Logging in as a registered user https://us1.my.wallarm.com/login takes you to the default threat prevention dashboard.

WAF overview


Architecture overview

The primary security functionality of the wallarm-ingress-controller is carried out by a load balancer service (with an external IP address) integrated into the Wallarm WAF, which acts as a node instance to the Wallarm cloud API.

A node instance is bound to a Wallarm tenant , which can be considered a distinct environment of client resources, services, and infrastructure.

The component details below depict an example from a Kosmos UI–based installation into a vCluster running on an MKS host cluster.

Note: The wallarm-ingress namespace is automatically created via UI install (all namespaced Kubernetes components are installed into it).

Architecture overview

Primary components

Primary components details ### Services
k get svc -n wallarm-ingress
NAME                                           TYPE           CLUSTER-IP       EXTERNAL-IP                                                                       PORT(S)                      AGE
wallarm-ingress-controller                     LoadBalancer   10.100.121.105   ac1e56aba465b4e40977ac9814095940-4023961676.elb.ap-northeast-1.samsungspc.cloud   80:32559/TCP,443:32207/TCP   4d21h
wallarm-ingress-controller-admission           ClusterIP      10.100.183.137   <none>                                                                            443/TCP                      4d21h
wallarm-ingress-controller-wallarm-tarantool   ClusterIP      10.100.129.20    <none>                                                                            3313/TCP                     4d21h
  • Primary security functionality is carried out by an external load-balancer service (i.e. - the wallarm-ingress-controller service) integrated with the Wallarm cloud API

  • Two additional services are created:

    • wallarm-ingress-controller-admission
    • wallarm-ingress-controller-wallarm-tarantool

Ensure the external IP of the wallarm-ingress-controller service is reachable on its listener ports:

nc -vz ac1e56aba465b4e40977ac9814095940-4023961676.elb.ap-northeast-1.samsungspc.cloud 443
Connection to ac1e56aba465b4e40977ac9814095940-4023961676.elb.ap-northeast-1.samsungspc.cloud port 443 [tcp/https] succeeded!

Deployments, replicasets, and pods

k get deployments,replicasets,pods -n wallarm-ingress
NAME                                                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/wallarm-ingress-controller                     1/1     1            1           4d22h
deployment.apps/wallarm-ingress-controller-wallarm-tarantool   1/1     1            1           4d22h
NAME                                                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/wallarm-ingress-controller-7bcfb684d7                     1         1         1       4d22h
replicaset.apps/wallarm-ingress-controller-wallarm-tarantool-76777844d8   1         1         1       4d22h
NAME                                                                READY   STATUS    RESTARTS   AGE
pod/wallarm-ingress-controller-7bcfb684d7-qvxmd                     4/4     Running   0          4d22h
pod/wallarm-ingress-controller-wallarm-tarantool-76777844d8-f6clk   3/3     Running   0          4d22h
  • Deployments control replicasets, which in turn control pods.
  • Once ingress is set up and associated with a backend service, web traffic will appear in the wallarm-ingress-controller pod logs.
  • Configuration errors also show up in these logs.

IngressClass

k get ingressclass
NAME              CONTROLLER               PARAMETERS   AGE
wallarm-ingress   k8s.io/wallarm-ingress   <none>       5d

The wallarm-ingress ingress class is installed at the cluster level. If other ingress classes are installed, ingress objects must explicitly reference this name.


Secrets

k get secrets -n wallarm-ingress
NAME                                    TYPE                 DATA   AGE
controller-secret                       Opaque               1      5d
sh.helm.release.v1.wallarm-ingress.v1   helm.sh/release.v1   1      5d
wallarm-ingress-admission               Opaque               3      5d
  • The Wallarm API token (added via UI install) is stored as a base64-encoded string in the controller-secret.
  • An invalid or empty token prevents the controller pod from reaching the cloud API.

Example error log:

2025/03/29 16:38:38 [error] 167#167: *11770 WALLARM:ACL: unable to open database file. Folder paths: acl "/opt/wallarm/var/lib/wallarm-acl", mmdb "/opt/wallarm/var/lib/wallarm-acl"

Valid secret contents:

apiVersion: v1
data:
  token: <base-64-encoded-token-string>
kind: Secret
metadata:
  name: controller-secret
  namespace: wallarm-ingress
type: Opaque
---

Additional components

Additional components details

Configmaps

k get configmaps -n wallarm-ingress
NAME                         DATA   AGE
kube-root-ca.crt             1      147m
wallarm-ingress-controller   8      147m

Endpoints and endpoint slices

k get endpoints -n wallarm-ingress
NAME                                           ENDPOINTS                                AGE
wallarm-ingress-controller                     172.18.105.208:443,172.18.105.208:8080   148m
wallarm-ingress-controller-admission           172.18.105.208:8443                      148m
wallarm-ingress-controller-wallarm-tarantool   172.18.151.117:3313                      148m
k get endpointslices -n wallarm-ingress
NAME                                                 ADDRESSTYPE   PORTS      ENDPOINTS        AGE
wallarm-ingress-controller-admission-6g7lz           IPv4          8443       172.18.105.208   149m
wallarm-ingress-controller-cljx9                     IPv4          443,8080   172.18.105.208   149m
wallarm-ingress-controller-wallarm-tarantool-74j7k   IPv4          3313       172.18.151.117   149m

Service accounts

k get serviceaccounts -n wallarm-ingress
NAME              SECRETS   AGE
default           0         150m
wallarm-ingress   0         150m

Leases

k get leases -n wallarm-ingress
NAME                     HOLDER                                        AGE
wallarm-ingress-leader   wallarm-ingress-controller-59c94584c7-nm955   150m

Roles and role bindings

k get roles -n wallarm-ingress
NAME              CREATED AT
wallarm-ingress   2025-04-16T16:53:41Z
k get rolebindings -n wallarm-ingress
NAME              ROLE                   AGE
wallarm-ingress   Role/wallarm-ingress   151m

Getting started (Wallarm UI)

To install Wallarm WAF ingress, you need a Wallarm API token.

It can be obtained in two ways:

  1. From Devspacesecret
  2. From Wallarm UI

This token is required for installation via UI or CLI.

Obtaining a Token from Devspacesecret

Devspace secrets and Wallarm token

Every devspace has a corresponding devspacesecret, which contains a base64-encoded Wallarm token.

Note: The default devspacesecret name for every devspace is wallarm-token. Secrets are differentiated by devspace using the Namespace value, which follows the naming convention: loft-p-<devspace-name>


Example commands

Check devspace details:

kosmos get devspace devspace-waf-testing
Output Output:
IDOWNERCREATED AT
devspace-waf-testingdevspace-ownerAug 08, 2025 10:25:34

List devspacesecrets:

kosmos list devspacesecrets
Output
NAMENAMESPACE
wallarm-tokenloft-p-cjihrig-test-devspace-stg-1
wallarm-tokenloft-p-int-joyentproduct-stg-testing
wallarm-tokenloft-p-devspace-waf-testing
wallarm-tokenloft-p-test-devspace
wallarm-tokenloft-p-khang-devspace-300
wallarm-tokenloft-p-khang-devspace2
wallarm-tokenloft-p-paul-devspace-1
wallarm-tokenloft-p-rpk-vnode-test
wallarm-tokenloft-p-kanth-test-jun24
wallarm-tokenloft-p-srin

Retrieve the Wallarm token for a specific devspace:

kosmos get devspacesecret --name wallarm-token --devspace devspace-waf-testing -o yaml
Output metadata: creationTimestamp: "2025-08-08T17:25:35Z" finalizers: - devspacesecret/finalizer generation: 1 name: wallarm-token namespace: loft-p-devspace-waf-testing resourceVersion: "788164862" uid: 235883f9-393d-4f25-8f14-386c43f87dc7 spec: data: token: description: Secret containing a Wallarm token displayName: Wallarm Token status: {}

Decoding the token

From the YAML output, the field:

  • spec.data.token is the base64-encoded Wallarm API token that corresponds to this devspace (as a Wallarm node).
  • The token must be decoded to a plain-text string before it can be used for Helm chart or UI app installation of the Wallarm ingress controller.
  • On Linux / macOS, decode the token with:
echo "<base64-encoded-wallarm-token-value>" | base64 -d

Generating a Token From Wallarm UI

To generate Wallarm token. Navigate to https://us1.my.wallarm.com/settings/api-tokens , and select Create Token

Generate token:

Wallarm token generation

  • Important: In the Token application dropdown, be sure to select type Deployment (as this provides the token with the Deploy source-role permission set)
    • Token TTL (or lack thereof) is up to the user

Create token:

Create token

  • Once generated - a token’s plain text string can be retrieved by clicking the hamburger menu to the right, and selecting ‘Copy Token

Copy token:

Copy token

This token value will be needed for install (either via UI or CLI install) of the wallarm-ingress-controller application stack (highlighted in further steps)


Host cluster installation procedure

Wallarm WAF Installation in Kosmos Cluster

At this point only direct installation via Helm chart is supported.

Create a values.yaml file - of the following form:

Create values.yaml file
controller:
  config:
    use-forwarded-headers: "true"
    enable-real-ip: "true"
    forwarded-for-header: "X-Forwarded-For"
  ingressClass: wallarm-ingress
  ingressClassResource:
    controllerValue: k8s.io/wallarm-ingress
    name: wallarm-ingress
  service:
    enableHttp: false
  wallarm:
    apiHost: us1.api.wallarm.com
    enabled: true
    token: <wallarm-api-token>


Note: The token value should be the plain-text (non-base64) version of the Wallarm token obtained in previous steps.

To install the Wallarm WAF helm chart, drop into the Kube context of your target cluster - &:

Install the Wallarm WAF Helm chart
# Seed vars; copy values.yaml contents into a file
export wallarm_ns="wallarm-ingress"
export release_name="wallarm-ingress"
export chart_version="5.3.10"

# Create namespace
kubectl create namespace ${wallarm_ns}

# Add Wallarm Helm repo
helm repo add wallarm https://charts.wallarm.com
helm repo update wallarm

# Install the Helm chart
helm install --version ${chart_version} ${release_name} wallarm/wallarm-ingress -n ${wallarm_ns}

Check to make sure the Helm chart is in deployed status:

helm list -n wallarm-ingress
Expected Helm chart output:
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
wallarm-ingress wallarm-ingress 1               2025-08-15 12:03:39.970757067 -0700 PDT deployed        wallarm-ingress-5.3.10  5.3.10

Check expected pods in the wallarm-ingress namespace:
kubectl get pods -n wallarm-ingress
Expected pod output
NAME                                                            READY   STATUS    RESTARTS   AGE
wallarm-ingress-controller-5ffd7f9c47-zzmpx                     4/4     Running   0          3h2m
wallarm-ingress-controller-wallarm-tarantool-697d8759b6-6m954   3/3     Running   0          3h2m

Check the pod logs on the controller pod, healthy logs should look as such:
kubectl logs -f wallarm-ingress-controller-5ffd7f9c47-zzmpx -n wallarm-ingress
Healthy logs example

Defaulted container "controller" out of: controller, cron, collectd, api-firewall, addnode (init)
-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:       5.3.10
  Build:         git-2eae146
  Repository:    https://gitlab-ci-token:glcbt-64_tqU3JvjcR6hwNYkyp4TN@gl.wallarm.com/wallarm-node/ingress.git
  nginx version: nginx/1.25.5

-------------------------------------------------------------------------------

W0815 19:05:00.550209       8 client_config.go:659] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I0815 19:05:00.550456       8 main.go:205] "Creating API client" host="https://172.20.0.1:443"
I0815 19:05:00.559729       8 main.go:248] "Running in Kubernetes cluster" major="1" minor="31" git="v1.31.7" state="clean" commit="da53587841b4960dc3bd2af1ec6101b57c79aff4" platform="linux/amd64"
I0815 19:05:00.659503       8 main.go:101] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
I0815 19:05:00.677518       8 ssl.go:535] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key"
I0815 19:05:00.687116       8 nginx.go:271] "Starting NGINX Ingress controller"
I0815 19:05:00.694669       8 event.go:377] Event(v1.ObjectReference{Kind:"ConfigMap", Namespace:"wallarm-ingress", Name:"wallarm-ingress-controller", UID:"91fbfe7c-f1b4-4ff1-b656-062436bb8883", APIVersion:"v1", ResourceVersion:"313131", FieldPath:""}): type: 'Normal' reason: 'CREATE' ConfigMap wallarm-ingress/wallarm-ingress-controller
I0815 19:05:01.887952       8 nginx.go:317] "Starting NGINX process"
I0815 19:05:01.888153       8 leaderelection.go:254] attempting to acquire leader lease wallarm-ingress/wallarm-ingress-leader...
I0815 19:05:01.888427       8 nginx.go:337] "Starting validation webhook" address=":8443" certPath="/usr/local/certificates/cert" keyPath="/usr/local/certificates/key"
I0815 19:05:01.888658       8 controller.go:194] "Configuration changes detected, backend reload required"
I0815 19:05:01.900746       8 leaderelection.go:268] successfully acquired lease wallarm-ingress/wallarm-ingress-leader
I0815 19:05:01.901056       8 status.go:85] "New leader elected" identity="wallarm-ingress-controller-5ffd7f9c47-zzmpx"
I0815 19:05:01.930403       8 controller.go:214] "Backend successfully reloaded"
I0815 19:05:01.930446       8 controller.go:225] "Initial sync, sleeping for 1 second"
I0815 19:05:01.930526       8 event.go:377] Event(v1.ObjectReference{Kind:"Pod", Namespace:"wallarm-ingress", Name:"wallarm-ingress-controller-5ffd7f9c47-zzmpx", UID:"fe2f20e7-199c-4e02-a4f3-7cc06046875b", APIVersion:"v1", ResourceVersion:"313364", FieldPath:""}): type: 'Normal' reason: 'RELOAD' NGINX reload triggered due to a change in configuration

Important: A controller pod that cannot connect to the Wallarm cloud will continuously produce errors like:

Unhealthy logs example
2025/08/15 18:43:51 [error] 26#26: *1294 WALLARM:ACL: unable to open database file. Folder paths: acl "/opt/wallarm/var/lib/wallarm-acl", mmdb "/opt/wallarm/var/lib/wallarm-acl", client: 127.0.0.1, server: , request: "GET /is-dynamic-lb-initialized HTTP/1.1", host: "127.0.0.1:10246"
2025/08/15 18:44:00 [error] 26#26: *1351 WALLARM:ACL: unable to open database file. Folder paths: acl "/opt/wallarm/var/lib/wallarm-acl", mmdb "/opt/wallarm/var/lib/wallarm-acl", client: 127.0.0.1, server: , request: "GET /is-dynamic-lb-initialized HTTP/1.1", host: "127.0.0.1:10246"
2025/08/15 18:44:01 [error] 26#26: *1358 WALLARM:ACL: unable to open database file. Folder paths: acl "/opt/wallarm/var/lib/wallarm-acl", mmdb "/opt/wallarm/var/lib/wallarm-acl", client: 127.0.0.1, server: , request: "GET /is-dynamic-lb-initialized HTTP/1.1", host: "127.0.0.1:10246"
2025/08/15 18:44:10 [error] 26#26: *1415 WALLARM:ACL: unable to open database file. Folder paths: acl "/opt/wallarm/var/lib/wallarm-acl",

vCluster installation procedure

You can install Wallarm ingress in a vCluster using the Kosmos UI:

  1. Navigate to Ingress Controller in the sidebar.
  2. Select Wallarm.
  3. Provide the Wallarm API token.
  4. Install into the vCluster.

This automatically provisions the wallarm-ingress namespace and required components inside the vCluster.

Example vCluster spec ```yaml apiVersion: storage.kosmos.spcplatform.com/v1 kind: VirtualCluster metadata: name: namespace: spec: clusterRef: cluster: namespace: loft--v- virtualCluster: description: displayName: owner: user: sleepModeConfig: timezone: PDT#-25200 #(as example) templateRef: name: vcluster-pro version: 0.22.4 ```

Kosmos UI installation procedure

  • The wallarm-ingress-controller can be installed in a vCluster via Kosmos ‘Application Install’
  • This is a templated / pre-packaged installation of the Wallarm Helm install, aimed at a specific chart version, with values specific to the Loft vCluster integration
  • Prior to attempting UI app installation, it is necessary to create a kubernetes secret in your vCluster, containing the Wallarm WAF token (retrieved in the Getting Started section)
  • Drop into the kube context of your vCluster, create the namespace where the Wallarm components will be installed, and create the secret in said namespace (steps highlighted below)

Note: Use the plaintext (i.e. non-base64 encoded value) version of the Wallarm WAF token

Kosmos UI handles the Helm deployment inside the cluster.

kosmos use vcluster --name <vcluster-name> --devspace <devspace-name>

15:58:03 done Successfully updated kube context to use virtual cluster in devspace

kubectl create namespace wallarm-ingress

namespace/wallarm-ingress created

kubectl create secret generic wallarm-api-token --from-literal=token=<your wallarm api token here> -n wallarm-ingress

secret/wallarm-api-token created

  • After having created your secret - navigate to the vCluster’s UI pane:

    • https://console-.kosmos.spcplatform.com/devspaces//vclusters/
  • Navigate to the Apps section, and select “Install App”

    Install App

  • In the installation pane, select Wallarm-Ingress from the dropdown menu

    Select App

  • Wallarm secret key name must match the value used in our previous kubernetes secret creation command:

    • kubectl create secret generic wallarm-api-token --from-literal=token=...
  • Wallarm external secret name is the name of the secret (as demonstrated above).

    • Click “Install”
  • The UI will generate output, showing installation steps - resulting in a success message (on proper installation)

    installing successfully

  • To verify installation - from CLI, move into kube context of vCluster - and check helm installation details:

helm list -A

Output:

NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
wallarm-ingress wallarm-ingress 1               2025-04-16 16:53:27.519121854 +0000 UTC deployed        wallarm-ingress-5.3.10  5.3.10
  • The release should be in deployed status

    • For any other status (pending, failed) - check the status of the release
helm status wallarm-ingress -n wallarm-ingress

Direct Installation (CLI Helm Install - Alternative to Kosmos UI)

As mentioned, the UI installation is simply a templated installation of the Wallarm-Ingress Helm chart.

The chart values created by the UI install take the following form:

helm get values wallarm-ingress -n wallarm-ingress
controller:
  config:
    use-forwarded-headers: "true"
    enable-real-ip: "true"
    forwarded-for-header: "X-Forwarded-For"
  ingressClass: wallarm-ingress
  ingressClassResource:
    controllerValue: k8s.io/wallarm-ingress
    name: wallarm-ingress
  service:
    enableHttp: false
  wallarm:
    apiHost: us1.api.wallarm.com
    enabled: true
    token: <wallarm-api-token>
loft:
  name: <vcluster-name>
  project: <devspace-name>
  user:
    displayName: <kosmos-user-displayname>
    email: <kosmos-user-email>
    name: <kosmos-username>
    subject: <kosmos-user-email>
    teams:
    - displayName: <kosmos-team-displayname>
      name: <kosmos-team-name>
    username: <kosmos-username>
nameOverride: wallarm-ingress

Copy the contents above into a values.yaml file, filling in the necessary values (denoted by <..>). You can then install the Wallarm Ingress Controller chart directly via Helm.

Note: The templated UI application install explicitly installs version 5.3.10.

# Seed vars; copy contents with filled values of code block above into 'values.yaml' file
export wallarm_ns="wallarm-ingress"
export release_name="wallarm-ingress"
export chart_version="5.3.10"

# Create namespace
kubectl create namespace ${wallarm_ns}

# Add Wallarm Helm repo
helm repo add wallarm https://charts.wallarm.com
helm repo update wallarm

# Install the Helm chart
helm install --version ${chart_version} ${release_name} wallarm/wallarm-ingress -n ${wallarm_ns} -f values.yaml

Ingress implementation

The following example details steps for creating a simple webserver running as a deployment, exposed by a service. This service will be linked to an ingress, using the wallarm-ingress ingress class.

We will generate a self-signed SSL cert to make use of the HTTPS listener port (any backend exposed over HTTP will be flagged by security).

For this demo, we are in the kubectl context of our previously created vCluster mksdp-waf-vcluster.

Note: This process works for both vClusters and standard Kubernetes clusters.

List vClusters & Switch Context

kosmos list vclusters --devspace automation-devspace
| NAME          | CLUSTER       | DEVSPACE    | NAMESPACE       | STATUS    | AGE  |
|---------------|---------------|-------------|-----------------|-----------|------|
| aks-waf-vcluster   | aks-waf-ingress-2135417742 | automation-devspace | loft-p-james-automation-devspace | Ready  | 4d3h |
| dx-waf-vcluster    | dx-aws-sandbox-stg-apne2-eks     | automation-devspace | loft-p-automation-devspace | Ready  | 6d1h |
| mksdp-waf-vcluster | dx-spc-devpool-stg-apne1-mks     | automation-devspace | loft-p-automation-devspace | Ready  | 4d23h |
k config current-context
kosmos-vcluster-mksdp-waf-vcluster-automation-devspace

Reminder: Use kosmos use vcluster <vcluster-name> to switch to the vCluster’s kube context.


Create Namespace

Create and label a new namespace for webserver components:

k create namespace ingress-testing
namespace/ingress-testing created
k label namespaces ingress-testing name=ingress-testing --overwrite=true
namespace/ingress-testing labeled
k describe namespace ingress-testing
Name:         ingress-testing
Labels:       kubernetes.io/metadata.name=ingress-testing
              name=ingress-testing
Annotations:  <none>
Status:       Active

Create Self-Signed SSL Cert

For our DNS/webserver address, we will use ingress.testing.joyentqe.com.

Below, is a script that will allow us to generate a self-signed SSL cert for our domain

Click to expand
#! /bin/bash

# reference: https://devopscube.com/create-self-signed-certificates-openssl/

if [ "$#" -ne 3 ]
then
  echo "Error: No domain name argument provided"
  echo "Usage: Provide a domain name, org, and org unit as arguments"
  exit 1
fi

DOMAIN=$1
ORG=$2
ORG_UNIT=$3

# Create root CA & Private key

openssl req -x509 \
            -sha256 -days 356 \
            -nodes \
            -newkey rsa:2048 \
            -subj "/CN=${DOMAIN}/C=US/L=San Fransisco" \
            -keyout rootCA.key -out rootCA.crt

# Generate Private key

openssl genrsa -out ${DOMAIN}.key 2048

# Create csf conf

cat > csr.conf <<EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = US
ST = California
L = San Fransisco
O = ${ORG}
OU = ${ORG_UNIT}
CN = ${DOMAIN}

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = ${DOMAIN}
DNS.2 = www.${DOMAIN}
IP.1 = 192.168.1.5
IP.2 = 192.168.1.6

EOF

# create CSR request using private key

openssl req -new -key ${DOMAIN}.key -out ${DOMAIN}.csr -config csr.conf

# Create a external config file for the certificate

cat > cert.conf <<EOF

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = ${DOMAIN}

EOF

# Create SSl with self signed CA

openssl x509 -req \
    -in ${DOMAIN}.csr \
    -CA rootCA.crt -CAkey rootCA.key \
    -CAcreateserial -out ${DOMAIN}.crt \
    -days 365 \
    -sha256 -extfile cert.conf

Prepare and Execute Script

It is recommended to create a directory space, and cd into it (as the script will generate numerous certificate assets)

Script arguments are as follows:

  • $1: Domain/URL to be used by webserver
  • $2: Organization (e.g. joyent)
  • $3: Organization unit (e.g qa)
$ ls -la | grep ssl.sh
-rwxr-xr-x   1 devspace-owner  staff  1600 Apr 15 07:36 ssl.sh

$ mkdir ingress-testing-cert && cp ssl.sh ingress-testing-cert && cd ingress-testing-cert
$ ./ssl.sh ingress.testing.joyentqe.com joyent qe
Certificate request self-signature ok
subject=C=US, ST=California, L=San Fransisco, O=joyent, OU=qe, CN=ingress.testing.joyentqe.com

Generated Certificate Assets

.
├── cert.conf
├── csr.conf
├── ingress.testing.joyentqe.com.crt
├── ingress.testing.joyentqe.com.csr
├── ingress.testing.joyentqe.com.key
├── rootCA.crt
├── rootCA.key
├── rootCA.srl
└── ssl.sh

Create TLS Secret

Create a TLS secret from the self-signed cert:

k create secret -n ingress-testing tls ingress-testing-joyentqe --cert=ingress.testing.joyentqe.com.crt --key=ingress.testing.joyentqe.com.key -o yaml > ingress-testing-joyentqe.secret

k get secret -n ingress-testing
NAME                          TYPE                DATA   AGE
ingress-testing-joyentqe      kubernetes.io/tls   2      13s

Note: Reference this secret (ingress-testing-joyentqe) in the TLS section of the ingress definition.


Create Webserver & Ingress Components

Apply the webserver-components.yaml file containing:

  • Webserver index page configmap (nginx-configmap)
  • Webserver nginx configuration configmap (nginx-defaultconf-configmap)
  • Webserver deployment spec (nginx-deployment)
  • Ingress definition
webserver-components.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configmap
  namespace: ingress-testing
data:
  index.html: |
    <!DOCTYPE html>
    <html>
    <head>
      <title>vCluster 'mksdp-waf-vcluster' Index Page</title>
    </head>
    <body style="background-color:powderblue">
      <h1>Hello! I am an index page from within a pod running on vCluster => "mksdp-waf-vcluster"!</h1>
    </body>
    </html>
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-defaultconf-configmap
  namespace: ingress-testing
data:
  default.conf: |
    server {
        listen       80;
        listen  [::]:80;
        server_name  localhost;

        #access_log  /var/log/nginx/host.access.log  main;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        location /vcluster/ {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: ingress-testing
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: nginx
      namespace: ingress-testing
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        volumeMounts:
          - mountPath: /usr/share/nginx/html
            name: nginx-config-volume
          - mountPath: /etc/nginx/conf.d
            name: nginx-default-volume
      restartPolicy: Always
      volumes:
        - name: nginx-config-volume
          configMap:
            name: nginx-configmap
        - name: nginx-default-volume
          configMap:
            name: nginx-defaultconf-configmap
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    #cert-manager.io/cluster-issuer: kubeissuer
    kubernetes.io/ingress.class: wallarm-ingress
    nginx.ingress.kubernetes.io/rewrite-target: /
  name: ingress-demo
  namespace: ingress-testing
spec:
  ingressClassName: wallarm-ingress
  tls:
    - hosts:
        - ingress.testing.joyentqe.com
      secretName: ingress-testing-joyentqe
  rules:
    - host: ingress.testing.joyentqe.com
      http:
        paths:
          - backend:
              service:
                name: nginx-svc
                port:
                  number: 80
            path: /
            pathType: Prefix

Apply the components file to create resources

k apply -f webserver-components.yaml
configmap/nginx-configmap created
configmap/nginx-defaultconf-configmap created
deployment.apps/nginx-deployment created
ingress.networking.k8s.io/ingress-demo created

Expose the deployment as a service (linking it to ingress & Wallarm ingress class):

k expose deployment nginx-deployment --selector='app=nginx' --name=nginx-svc --port=80 -n ingress-testing
service/nginx-svc exposed

Verify that ingress is healthy and reachable:

k describe ing ingress-demo -n ingress-testing
Click to expand
Name:             ingress-demo
Labels:           <none>
Namespace:        ingress-testing
Address:          ac1e56aba465b4e40977ac9814095940-4023961676.elb.ap-northeast-1.samsungspc.cloud
Ingress Class:    wallarm-ingress
Default backend:  <default>
TLS:
  ingress-testing-joyentqe terminates ingress.testing.joyentqe.com
Rules:
  Host                          Path  Backends
  ----                          ----  --------
  ingress.testing.joyentqe.com
                                /   nginx-svc:80
Annotations:                    kubernetes.io/ingress.class: wallarm-ingress
                                nginx.ingress.kubernetes.io/rewrite-target: /
Events:                         <none>

Test connectivity:

curl -kiX GET "https://ingress.testing.joyentqe.com/"
<!DOCTYPE html>
<html>
<head>
  <title>vCluster 'mksdp-waf-vcluster' Index Page</title>
</head>
<body style="background-color:powderblue">
  <h1>Hello! I am an index page from within a pod running on vCluster => "mksdp-waf-vcluster"!</h1>
</body>
</html>

Ingress Annotations

Iinn order for web traffic to be inspected by the Wallarm WAF, we must annotate our ingress - designating it with a unique ‘Application ID’ (used by the Wallarm cloud API)

Annotate ingress for Wallarm WAF traffic analysis:

k annotate ingress ingress-demo -n ingress-testing nginx.ingress.kubernetes.io/wallarm-mode=monitoring
k annotate ingress ingress-demo -n ingress-testing nginx.ingress.kubernetes.io/wallarm-application="123456"

Both annotations are necessary for traffic inspection. Traffic becomes available in Wallarm UI (denoted by the app ID).

Ingress annotation


Traffic analysis and security features

Wallarm WAF integration provides several built-in security capabilities, including:

  • IP whitelisting & blacklisting
  • Path-based inspection
  • Attack detection

Testing WAF functionality

A quick way to verify WAF functionality is to emulate a path-traversal attack. In this example, we attempt to access /etc/passwd through the ingress:

curl -kiX GET "https://ingress.testing.joyentqe.com/etc/passwd"

Checking Wallarm controller logs

After the request, review the Wallarm ingress controller logs:

k logs -f wallarm-ingress-controller-7bcfb684d7-qvxmd -n wallarm-ingress

Sample output:

172.18.78.164 - - [15/Apr/2025:19:42:29 +0000] "GET /etc/passwd HTTP/2.0" 404 153 "-" "curl/8.6.0" 49 0.006 [ingress-testing-nginx-svc-80] [] 172.18.151.117:80 153 0.006 404 4169fd2c108affe0391022355b3f0801
172.18.78.164 - - [15/Apr/2025:19:44:25 +0000] "GET /etc/passwd HTTP/2.0" 404 555 "-" "Mozilla/5.0 ..." 480 0.006 [ingress-testing-nginx-svc-80] [] 172.18.151.117:80 555 0.007 404 ac8c14849fa67139a11d140880d15c1f

Result

  • The webserver responds with 404 because no such route exists in its configuration.
  • The Wallarm WAF still inspects the traffic and logs the attempt in the Wallarm UI under the Attacks section.

traffic analysis

Edit this page on GitHub