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.

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).

Primary components
Primary components details
### Servicesk 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-admissionwallarm-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-controllerpod 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:
- From Devspacesecret
- 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:| ID | OWNER | CREATED AT |
|---|---|---|
| devspace-waf-testing | devspace-owner | Aug 08, 2025 10:25:34 |
List devspacesecrets:
kosmos list devspacesecrets
Output
| NAME | NAMESPACE |
|---|---|
| wallarm-token | loft-p-cjihrig-test-devspace-stg-1 |
| wallarm-token | loft-p-int-joyentproduct-stg-testing |
| wallarm-token | loft-p-devspace-waf-testing |
| wallarm-token | loft-p-test-devspace |
| wallarm-token | loft-p-khang-devspace-300 |
| wallarm-token | loft-p-khang-devspace2 |
| wallarm-token | loft-p-paul-devspace-1 |
| wallarm-token | loft-p-rpk-vnode-test |
| wallarm-token | loft-p-kanth-test-jun24 |
| wallarm-token | loft-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:Decoding the token
From the YAML output, the field:
spec.data.tokenis 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:
- 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:

- 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:

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:
- Navigate to Ingress Controller in the sidebar.
- Select Wallarm.
- Provide the Wallarm API token.
- 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: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
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/
- https://console-
Navigate to the Apps section, and select “Install App”

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

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)

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).

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
404because 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.
