Skip to content

NGFW Configuration Reference — TLSStress.Art DUT Mode

Who this is for: The network engineer responsible for configuring the firewall being tested (the Device Under Test — DUT). This document contains every VLAN, IP address, route, and TLS policy the NGFW must be configured with before the test-bed can generate traffic.

Author: André Luiz Gallon — agallon@tlsstress.art | Version: v3.6.0

Scope status (post-Scope-Freeze 2026-05-10) — See ARCHITECTURE.md for the canonical 37 MÓDULOs + 7 Test Kinds + DOM/CPOS/PIE-PA safety architecture. ADRs 0014, 0019-0025 cover post-Freeze additions.


Table of Contents

  1. How the Test-Bed Works
  2. Physical Connectivity
  3. Complete VLAN and IP Reference
  4. NGFW Interface Configuration
  5. Routing Table
  6. PKI — The Two CAs
  7. TLS Inspection Policy
  8. Vendor Configuration Examples
  9. Cisco FTD (FMC)
  10. Cisco FTD (FDM)
  11. Cisco ASA
  12. FortiGate
  13. Palo Alto PAN-OS
  14. Check Point
  15. Verification
  16. Troubleshooting

1. How the Test-Bed Works

The TLSStress.Art places the NGFW in the middle of all HTTPS traffic between simulated users (agents) and simulated websites (personas). The NGFW must perform TLS inspection on every connection — this is exactly what is being measured.

┌─────────────────────────────────────────────────────────────────┐
│                   TLSStress.Art (Ubuntu + k3s)              │
│                                                                 │
│  browser-engine agents (VLAN 20 — 172.16.x.x)                      │
│  synthetic-load agents         (VLAN 30 — 172.17.x.x)                      │
└───────────────────────────┬─────────────────────────────────────┘
                            │  TLS Leg 1
                            │  Agents → NGFW
                            │  NGFW presents its own CA-signed cert
                            │  Agents trust ngfw-ca (installed in cluster)
                            ▼
              ┌─────────────────────────┐
              │   NGFW (Device Under    │  ◄── This is what is being tested
              │        Test)            │
              │                         │
              │  TLS Inspection Engine  │
              │  Decrypt → Inspect →    │
              │  Re-encrypt             │
              └─────────────┬───────────┘
                            │  TLS Leg 2
                            │  NGFW → Persona webservers
                            │  Persona certs signed by persona-ca
                            │  NGFW trusts persona-ca (installed on NGFW)
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│               20 Persona Webservers (Caddy + Kubernetes)        │
│                                                                 │
│  shop        VLAN 101 (US) — 198.32.10.0/24                    │
│  news        VLAN 102 (CN) — 202.112.10.0/24                   │
│  ...         ...                                               │
│  har-media   VLAN 120 (NG) — 196.32.0.0/24                     │
└─────────────────────────────────────────────────────────────────┘

Two TLS legs — two separate certificate trust relationships:

Leg Direction Who presents cert Who must trust it How
Leg 1 Agent → NGFW NGFW (forward-proxy cert) Agents (browser-engine + synthetic-load) ngfw-ca.crt installed in Kubernetes cluster
Leg 2 NGFW → Persona webservers Persona webserver (Caddy) NGFW persona-ca.pem installed in NGFW trust store

2. Physical Connectivity

Cabling

Ubuntu Server (test-bed)
  eth1 (802.1q trunk) ──────────► Nexus 9000 trunk port
                                        │
                                   VLAN trunk
                                   (all VLANs)
                                        │
                               ┌────────┴────────┐
                               │   Nexus 9000    │
                               └────────┬────────┘
                                        │
                             ┌──────────┴──────────┐
                             │   Access port(s)    │
                             │   to NGFW data      │
                             │   interfaces        │
                             └──────────┬──────────┘
                                        │
                                   ┌────┴────┐
                                   │  NGFW   │
                                   │  (DUT)  │
                                   └─────────┘

Nexus 9000 requirements

The Nexus 9000 must be configured with the following VLANs and trunk:

vlan 20,30,99,101-120,200-209

interface <trunk-to-ubuntu>
  switchport mode trunk
  switchport trunk allowed vlan 20,30,99,101-120,200-209

interface <to-ngfw-inside>           ! agent-side NGFW port
  switchport mode trunk
  switchport trunk allowed vlan 20,30

interface <to-ngfw-outside>          ! webserver-side NGFW port (Synthetic + Cloned Personas)
  switchport mode trunk
  switchport trunk allowed vlan 101-120,200-209

interface <to-ngfw-mgmt>             ! management NGFW port (optional)
  switchport mode access
  switchport access vlan 99

Note on VLAN 10 (removed in v3.7.0): the legacy single-Caddy Docker-mode webserver layer that lived on VLAN 10 / 10.20.30.0/24 was removed. Kubernetes is the single source of truth for DUT webservers — 20 Synthetic Personas on VLANs 101–120 + 10 Cloned Persona slots on VLANs 200–209.


3. Complete VLAN and IP Reference

3.0 NGFW Security Zone Mapping (v4.3, locked 2026-05-09)

The NGFW has 8 interfaces (or sub-interfaces on a trunk) distributed across 3 zones:

Zone VLANs Carries
TRUST / INSIDE 20, 30, 2900 Agent corporate LANs (browser-engine + synthetic-load) + control-plane stress agent (MAC + ARP/NDP)
UNTRUST / OUTSIDE 1982, 2001, 2809, 4338 VyOS routing/peer endpoints (OSPF, ISP/edge, BGP, MÓDULO SDWAN/CoR-N.Art local mode — legacy "VPN-REMOTE")
MGMT 99 Management — SNMP only

VLANs that do NOT terminate on the NGFW:

VLAN Reason
40 (cloner-isp) Cloner egress goes directly to public Internet — bypasses NGFW
101–120 (Synthetic Personas) Personas live BEHIND the VyOS-ISP pod (one country /24 per VLAN); the NGFW only sees the single edge link (VLAN 2001) — VyOS-ISP routes onward to each country
200–209 (Cloned Personas) Being deprecated — cloned personas migrate to country /24s alongside Synthetic ones

⚠️ Sections 3.3 and 4.2 below describe the LEGACY v3.x topology where personas terminated on NGFW sub-interfaces (one per VLAN 101–120, with NGFW gateway 10.1.x.1). For v4.3, personas live behind VyOS-ISP and the NGFW only has the single VLAN 2001 outside interface for all persona traffic. See docs/ARCHITECTURE.md "DUT network segments" for the corrected topology. Migration tracked separately (Personas v4.3 IP migration option B).

3.1 Agent VLANs (Inside — toward NGFW)

These are the subnets where the test agents live. The NGFW is the default gateway for agents.

VLAN Purpose Subnet NGFW Interface IP Agent IP range Protocol
20 browser-engine agents (real browser) 172.16.0.0/16 172.16.0.1 172.16.1.0 – 172.16.255.254 HTTPS (TCP 443)
30 synthetic-load agents (HTTP load) 172.17.0.0/16 172.17.0.1 172.17.1.0 – 172.17.255.254 HTTPS (TCP 443)

browser-engine agents generate real browser-style HTTPS with full TLS handshake and JavaScript. synthetic-load agents generate high-scale HTTP/2 and HTTP/3 load.

3.2 Management VLAN

VLAN Purpose Subnet Nexus 9000 IP NGFW mgmt IP K8s SNMP pod range
99 SNMP monitoring 100.127.252.0/24 100.127.252.2 100.127.252.3 100.127.252.10 – .49

The SNMP Exporter pod collects CPU, memory, and interface counters from both the Nexus 9000 and the NGFW to correlate traffic load with hardware performance.

3.3 Persona VLANs (Outside — toward Caddy webservers)

There are two groups of persona VLANs, both in the data path (NGFW → Caddy):

Synthetic Personas — target population is 100 personas (5 per country across 20 country LANs on VLANs 101–120), each persona living in its own Kubernetes namespace with content generated by its archetype seeder. During the v4.2 → v4.3 migration window the first persona of each country is provisioned (table below); F8.2 lands the remaining 80.

Each country LAN is backed by a public /24 prefix sourced from platform/network/public-ip-pool.yaml (NREN-anchored allocations re-validated at deploy time by tools/validate-ip-pool.sh). IP allocation convention (per country /24): .1 = VyOS-ISP country LAN attachment (gateway) — the NGFW only sees the single VLAN 2001 outside link in v4.3 — and .10 onward = personas.

VLAN Country Public /24 (primary) NREN / org First persona Archetype NGFW Interface IP (.1, legacy v3.x) Webserver IP (.10) DNS name Site type
101 US 198.32.10.0/24 Internet2 shop real-app 198.32.10.1 198.32.10.10 shop.us.persona.tlsstress.art E-Commerce (Saleor)
102 CN 202.112.10.0/24 CERNET news skin 202.112.10.1 202.112.10.10 news.cn.persona.tlsstress.art News Portal
103 IN 202.141.65.0/24 ERNET India blog skin 202.141.65.1 202.141.65.10 blog.in.persona.tlsstress.art Blog
104 DE 188.1.10.0/24 DFN docs skin 188.1.10.1 188.1.10.10 docs.de.persona.tlsstress.art Technical Documentation
105 JP 150.99.10.0/24 SINET gallery skin 150.99.10.1 150.99.10.10 gallery.jp.persona.tlsstress.art Image Gallery
106 UK 130.88.10.0/24 JANET stream skin 130.88.10.1 130.88.10.10 stream.uk.persona.tlsstress.art HLS Video Streaming
107 FR 193.51.10.0/24 RENATER download skin 193.51.10.1 193.51.10.10 download.fr.persona.tlsstress.art File Hosting
108 IT 193.205.10.0/24 GARR edu skin 193.205.10.1 193.205.10.10 edu.it.persona.tlsstress.art Learning Platform
109 BR 200.131.10.0/24 RNP gov skin 200.131.10.1 200.131.10.10 gov.br.persona.tlsstress.art Government Portal
110 CA 205.189.32.0/24 CANARIE cdn skin 205.189.32.1 205.189.32.10 cdn.ca.persona.tlsstress.art Asset CDN
111 RU 194.85.10.0/24 RUNNet api-rest mock 194.85.10.1 194.85.10.10 api-rest.ru.persona.tlsstress.art REST API
112 MX 200.23.10.0/24 CUDI api-graphql mock 200.23.10.1 200.23.10.10 api-graphql.mx.persona.tlsstress.art GraphQL API
113 AU 202.158.192.0/24 AARNet chat mock 202.158.192.1 202.158.192.10 chat.au.persona.tlsstress.art Chat / Messaging
114 ES 130.206.10.0/24 RedIRIS webhook mock 130.206.10.1 130.206.10.10 webhook.es.persona.tlsstress.art Webhooks
115 KR 134.75.10.0/24 KREONET telemetry mock 134.75.10.1 134.75.10.10 telemetry.kr.persona.tlsstress.art Analytics / Telemetry
116 ID 202.46.10.0/24 INHERENT ads mock 202.46.10.1 202.46.10.10 ads.id.persona.tlsstress.art Ad Network
117 NL 145.146.10.0/24 SURFnet har-saas har-replay 145.146.10.1 145.146.10.10 har-saas.nl.persona.tlsstress.art Enterprise SaaS (HAR replay)
118 SA 212.118.0.0/24 KACST har-social har-replay 212.118.0.1 212.118.0.10 har-social.sa.persona.tlsstress.art Social Network (HAR replay)
119 TR 193.140.10.0/24 ULAKBIM har-webmail har-replay 193.140.10.1 193.140.10.10 har-webmail.tr.persona.tlsstress.art Webmail (HAR replay)
120 NG 196.32.0.0/24 NgREN har-media har-replay 196.32.0.1 196.32.0.10 har-media.ng.persona.tlsstress.art Media Streaming (HAR replay)

Webserver IPs: each persona pod gets a single /32 IP from its country /24 (first persona = .10, additional personas in F8.2 = .11...14). If replicas > 1, additional IPs (.15...99) are assigned by HPA. The TLS certificate covers the full per-country range. The NGFW connects to the webserver IP directly (IP SAN validation). The NGFW Interface IP column reflects the legacy v3.x topology where the NGFW terminated each country LAN as a sub-interface; in v4.3 the NGFW only owns the single VLAN 2001 outside link and VyOS-ISP holds .1 on each country LAN (see §3.0 note).

Source of truth: personas.yaml (schema v4.3 — country attribute drives lookup; legacy vlan_id/subnet/gateway fields kept for backwards compat during migration and dropped per-entry as F8.2 lands) and platform/network/public-ip-pool.yaml (the 20 country /24 prefixes + offset convention).

Cloned Personas — 10 dynamic slots serving static site mirrors cloned from public websites:

VLAN Slot Subnet NGFW Interface IP Webserver IP(s) Content
200 clone-persona-1 10.2.1.0/27 10.2.1.1 10.2.1.2 Cloned site (file_server from PVC)
201 clone-persona-2 10.2.2.0/27 10.2.2.1 10.2.2.2 Cloned site (file_server from PVC)
202 clone-persona-3 10.2.3.0/27 10.2.3.1 10.2.3.2 Cloned site (file_server from PVC)
203 clone-persona-4 10.2.4.0/27 10.2.4.1 10.2.4.2 Cloned site (file_server from PVC)
204 clone-persona-5 10.2.5.0/27 10.2.5.1 10.2.5.2 Cloned site (file_server from PVC)
205 clone-persona-6 10.2.6.0/27 10.2.6.1 10.2.6.2 Cloned site (file_server from PVC)
206 clone-persona-7 10.2.7.0/27 10.2.7.1 10.2.7.2 Cloned site (file_server from PVC)
207 clone-persona-8 10.2.8.0/27 10.2.8.1 10.2.8.2 Cloned site (file_server from PVC)
208 clone-persona-9 10.2.9.0/27 10.2.9.1 10.2.9.2 Cloned site (file_server from PVC)
209 clone-persona-10 10.2.10.0/27 10.2.10.1 10.2.10.2 Cloned site (file_server from PVC)

Cloned Persona slots are assigned via Dashboard: PATCH /api/clone/persona-slots/{n} { "siteName": "<site>" }. Certs are signed by the same persona-ca-issuer as Synthetic Personas. The NGFW CA trust configuration is identical.

3.4 Summary — all subnets

VLAN Subnet Role NGFW interface IP
20 172.16.0.0/16 browser-engine agents 172.16.0.1
30 172.17.0.0/16 synthetic-load agents 172.17.0.1
99 100.127.252.0/24 SNMP management 100.127.252.3
101 198.32.10.0/24 (US, Internet2) shop 198.32.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
102 202.112.10.0/24 (CN, CERNET) news 202.112.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
103 202.141.65.0/24 (IN, ERNET India) blog 202.141.65.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
104 188.1.10.0/24 (DE, DFN) docs 188.1.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
105 150.99.10.0/24 (JP, SINET) gallery 150.99.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
106 130.88.10.0/24 (UK, JANET) stream 130.88.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
107 193.51.10.0/24 (FR, RENATER) download 193.51.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
108 193.205.10.0/24 (IT, GARR) edu 193.205.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
109 200.131.10.0/24 (BR, RNP) gov 200.131.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
110 205.189.32.0/24 (CA, CANARIE) cdn 205.189.32.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
111 194.85.10.0/24 (RU, RUNNet) api-rest 194.85.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
112 200.23.10.0/24 (MX, CUDI) api-graphql 200.23.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
113 202.158.192.0/24 (AU, AARNet) chat 202.158.192.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
114 130.206.10.0/24 (ES, RedIRIS) webhook 130.206.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
115 134.75.10.0/24 (KR, KREONET) telemetry 134.75.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
116 202.46.10.0/24 (ID, INHERENT) ads 202.46.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
117 145.146.10.0/24 (NL, SURFnet) har-saas 145.146.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
118 212.118.0.0/24 (SA, KACST) har-social 212.118.0.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
119 193.140.10.0/24 (TR, ULAKBIM) har-webmail 193.140.10.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
120 196.32.0.0/24 (NG, NgREN) har-media 196.32.0.1 (legacy v3.x; v4.3 routed via VyOS-ISP)
200 10.2.1.0/27 clone-persona-1 10.2.1.1
201 10.2.2.0/27 clone-persona-2 10.2.2.1
202 10.2.3.0/27 clone-persona-3 10.2.3.1
203 10.2.4.0/27 clone-persona-4 10.2.4.1
204 10.2.5.0/27 clone-persona-5 10.2.5.1
205 10.2.6.0/27 clone-persona-6 10.2.6.1
206 10.2.7.0/27 clone-persona-7 10.2.7.1
207 10.2.8.0/27 clone-persona-8 10.2.8.1
208 10.2.9.0/27 clone-persona-9 10.2.9.1
209 10.2.10.0/27 clone-persona-10 10.2.10.1

4. NGFW Interface Configuration

4.1 Required interfaces

The NGFW must have at minimum two physical interfaces (or one trunk):

Interface Connected to Carries VLANs Direction
Inside (agent-side) Nexus 9000 20, 30 Agents → NGFW
Outside (server-side) Nexus 9000 101–120, 200–209 NGFW → Persona webservers (Synthetic + Cloned)
Management (optional) Nexus 9000 99 SNMP monitoring only

4.2 Subinterface IPs to configure

For each VLAN, the NGFW needs a subinterface with the gateway IP listed in section 3. Example for a trunk-capable inside interface:

# Inside interface — agent-facing
VLAN 20  → IP 172.16.0.1/16   (browser-engine agent gateway)
VLAN 30  → IP 172.17.0.1/16   (synthetic-load agent gateway)

# Outside interface — webserver-facing (Synthetic Personas)
VLAN 101 → IP 10.1.1.1/27    (shop gateway)
VLAN 102 → IP 10.1.2.1/27    (news gateway)
VLAN 103 → IP 10.1.3.1/27    (blog gateway)
VLAN 104 → IP 10.1.4.1/27    (docs gateway)
VLAN 105 → IP 10.1.5.1/27    (gallery gateway)
VLAN 106 → IP 10.1.6.1/27    (stream gateway)
VLAN 107 → IP 10.1.7.1/27    (download gateway)
VLAN 108 → IP 10.1.8.1/27    (edu gateway)
VLAN 109 → IP 10.1.9.1/27    (gov gateway)
VLAN 110 → IP 10.1.10.1/27   (cdn gateway)
VLAN 111 → IP 10.1.11.1/27   (api-rest gateway)
VLAN 112 → IP 10.1.12.1/27   (api-graphql gateway)
VLAN 113 → IP 10.1.13.1/27   (chat gateway)
VLAN 114 → IP 10.1.14.1/27   (webhook gateway)
VLAN 115 → IP 10.1.15.1/27   (telemetry gateway)
VLAN 116 → IP 10.1.16.1/27   (ads gateway)
VLAN 117 → IP 10.1.17.1/27   (har-saas gateway)
VLAN 118 → IP 10.1.18.1/27   (har-social gateway)
VLAN 119 → IP 10.1.19.1/27   (har-webmail gateway)
VLAN 120 → IP 10.1.20.1/27   (har-media gateway)

# Outside interface — webserver-facing (Cloned Persona slots)
VLAN 200 → IP 10.2.1.1/27    (clone-persona-1 gateway)
VLAN 201 → IP 10.2.2.1/27    (clone-persona-2 gateway)
VLAN 202 → IP 10.2.3.1/27    (clone-persona-3 gateway)
VLAN 203 → IP 10.2.4.1/27    (clone-persona-4 gateway)
VLAN 204 → IP 10.2.5.1/27    (clone-persona-5 gateway)
VLAN 205 → IP 10.2.6.1/27    (clone-persona-6 gateway)
VLAN 206 → IP 10.2.7.1/27    (clone-persona-7 gateway)
VLAN 207 → IP 10.2.8.1/27    (clone-persona-8 gateway)
VLAN 208 → IP 10.2.9.1/27    (clone-persona-9 gateway)
VLAN 209 → IP 10.2.10.1/27   (clone-persona-10 gateway)

# Management interface
VLAN 99  → IP 100.127.252.3/24 (SNMP monitoring)

4.3 Security zones

Create two security zones on the NGFW:

Zone name Interfaces Trust level
agents VLAN 20, VLAN 30 Lower (clients — untrusted traffic source)
personas VLANs 101–120, 200–209 Higher (servers — inspect traffic going here)

5. Routing Table

The NGFW must be able to route traffic between the agent and persona subnets. Since it is the gateway for all subnets, the connected routes cover local forwarding. No static routes are strictly required unless the NGFW needs a management default route.

Destination Next Hop Interface Purpose
172.16.0.0/16 directly connected Inside.20 browser-engine agents
172.17.0.0/16 directly connected Inside.30 synthetic-load agents
20 × country /24 prefixes (see §3.3) directly connected Outside.101–120 Synthetic Persona webservers (one country LAN per VLAN, per v4.3 schema)
10.2.1.0/2710.2.10.0/27 directly connected Outside.200–209 Cloned Persona slots
100.127.252.0/24 directly connected Mgmt.99 SNMP management
0.0.0.0/0 management network GW Management Internet access for updates (optional)

Policy-based routing: some NGFWs apply routing decisions per security policy rule. Ensure your access policy allows traffic from agents zone to personas zone on TCP 443 (and UDP 443 for HTTP/3 / QUIC).


6. PKI — The Two CAs

This is the most critical part of the NGFW configuration. There are two completely different CAs, each used for a different TLS leg.

6.1 CA for Leg 2 — persona-ca-issuer CA (import INTO the NGFW)

What it is: the internal CA used by cert-manager (persona-ca-issuer ClusterIssuer in platform/pki/) to sign the TLS certificates of all 20 Synthetic Persona webservers and all 10 Cloned Persona slots (Caddy).

Why the NGFW needs it: in TLS Leg 2 (NGFW → webserver), the NGFW acts as a TLS client and must validate the server certificate presented by Caddy. If the NGFW doesn't trust this CA, it will reject the connection with a certificate validation error.

How to export it from the cluster:

# On the Ubuntu server (after running k8s-dut-up.sh or k8s-install.sh)
kubectl get secret persona-ca-bundle -n web-agents \
  -o jsonpath='{.data.ca\.crt}' | base64 -d > persona-ca.pem

# Verify the certificate
openssl x509 -in persona-ca.pem -text -noout | grep -E "Subject:|Issuer:|Not After"

Expected output:

Subject: O=Web Agent Cluster, OU=Persona PKI, CN=Persona CA
Issuer:  O=Web Agent Cluster, OU=Persona PKI, CN=Persona CA
Not After: <date ~10 years from cluster creation>

Where to import it on the NGFW: see section 8 for vendor-specific instructions. Generally: trusted CA store / SSL inspection trusted CAs.

This single CA signs certs for all 30 webserver VLANs (20 Synthetic Personas on VLANs 101–120 + 10 Cloned Persona slots on VLANs 200–209). You only need to import one CA into the NGFW.

6.2 CA for Leg 1 — ngfw-ca (export FROM the NGFW, install in cluster)

What it is: the CA the NGFW uses to sign the forward-proxy certificates it presents to the agents during TLS Leg 1. This is the NGFW's own interception CA.

Why the cluster needs it: browser engine (Node.js) and synthetic-load engine (Go) agents validate the server certificate during every HTTPS connection. If they don't trust the NGFW's CA, every connection will fail with CERT_AUTHORITY_INVALID or similar.

How to export it from each NGFW vendor:

Vendor Where to find it Export format
Cisco FTD (FMC) Objects → PKI → CA Certificates → select intercept CA → Export PEM
Cisco FTD (FDM) Policies → SSL → Trusted CA → export PEM
Cisco ASA crypto ca export <trustpoint> certificate PEM (copy from terminal)
FortiGate Security Profiles → SSL/SSH Inspection → CA Certificate → Download PEM
Palo Alto Device → Certificate Management → Certificates → select forward-trust cert → Export PEM
Check Point SmartConsole → Gateways → HTTPS Inspection → CA Certificate → Export PEM or Base64
Huawei USG System → PKI → CA Certificate → Export PEM
Meraki MX Security & SD-WAN → Content Filtering → SSL Inspection → Download CA Certificate PEM

How to install it in the cluster:

# Replace with the actual path to the exported PEM file
kubectl create configmap ngfw-ca \
  -n web-agents \
  --from-file=ngfw-ca.crt=./ngfw-ca.pem \
  --dry-run=client -o yaml | kubectl apply -f -

# Verify it was applied
kubectl get configmap ngfw-ca -n web-agents -o yaml | grep 'ngfw-ca.crt' -A 3

# Restart agents to pick up the new CA
kubectl rollout restart deployment/web-agent  -n web-agents
kubectl rollout restart deployment/k6-agent   -n web-agents
kubectl rollout status  deployment/web-agent  -n web-agents
kubectl rollout status  deployment/k6-agent   -n web-agents

7. TLS Inspection Policy

7.1 What to inspect

Configure the TLS inspection policy to decrypt and inspect all HTTPS traffic between the agent subnets and the persona subnets:

Source Destination Port Action
172.16.0.0/16 (browser engine) 10.1.0.0/16 (Synthetic Personas) TCP 443 Decrypt & Inspect
172.17.0.0/16 (synthetic-load engine) 10.1.0.0/16 (Synthetic Personas) TCP 443 Decrypt & Inspect
172.16.0.0/16 (browser engine) 10.1.0.0/16 (Synthetic Personas) UDP 443 Decrypt & Inspect (QUIC/HTTP3)
172.17.0.0/16 (synthetic-load engine) 10.1.0.0/16 (Synthetic Personas) UDP 443 Decrypt & Inspect (QUIC/HTTP3)
172.16.0.0/16 (browser engine) 10.2.0.0/16 (Cloned Persona slots) TCP 443 Decrypt & Inspect
172.17.0.0/16 (synthetic-load engine) 10.2.0.0/16 (Cloned Persona slots) TCP 443 Decrypt & Inspect
172.16.0.0/16 (browser engine) 10.2.0.0/16 (Cloned Persona slots) UDP 443 Decrypt & Inspect (QUIC/HTTP3)
172.17.0.0/16 (synthetic-load engine) 10.2.0.0/16 (Cloned Persona slots) UDP 443 Decrypt & Inspect (QUIC/HTTP3)

7.2 TLS versions

The Caddy webservers support TLS 1.2 and TLS 1.3. Configure the NGFW to inspect both:

  • Minimum: TLS 1.2
  • Maximum: TLS 1.3
  • Disable: TLS 1.1, TLS 1.0, SSL 3.0

7.3 Cipher suites

Caddy uses only ECDHE+AEAD cipher suites (ECDSA certificates). Ensure your inspection policy does not downgrade to RSA or CBC ciphers:

TLS_AES_256_GCM_SHA384          (TLS 1.3)
TLS_AES_128_GCM_SHA256          (TLS 1.3)
TLS_CHACHA20_POLY1305_SHA256    (TLS 1.3)
ECDHE-ECDSA-AES256-GCM-SHA384  (TLS 1.2)
ECDHE-ECDSA-AES128-GCM-SHA256  (TLS 1.2)
ECDHE-ECDSA-CHACHA20-POLY1305  (TLS 1.2)

7.4 HTTP/3 (QUIC) — important note

The synthetic-load agent can generate HTTP/3 (QUIC over UDP 443). HTTP/3 TLS inspection is harder for NGFWs and is one of the key metrics being measured. Check your NGFW vendor documentation for QUIC inspection support:

  • If QUIC inspection is supported: enable it and include UDP 443 in the inspection policy.
  • If QUIC inspection is not supported (or you want to measure only HTTP/2): add a rule to block or reset UDP 443, which forces agents to fall back to HTTP/2 over TCP. This is a valid test scenario — it measures the impact of forcing QUIC-capable clients to downgrade.

7.5 Certificate validation on Leg 2

The NGFW must validate the server certificate during Leg 2 (NGFW → Caddy). Ensure:

  • Server certificate validation: Enabled (not bypassed)
  • Trusted CA store: includes persona-ca.pem (see section 6.1) — this single CA covers both Synthetic Personas (VLANs 101–120) and Cloned Persona slots (VLANs 200–209)
  • Certificate revocation: CRL/OCSP can be disabled — this is a lab with no revocation infrastructure

8. Vendor Configuration Examples

8.1 Cisco FTD — Firepower Management Center

Step 1: Import persona-ca (trust persona webserver certs)

  1. Objects → PKI → Trusted CAs → Add Trusted CA
  2. Name: Persona-CA
  3. Upload persona-ca.pem
  4. Click Save

Step 2: Export ngfw-ca (so agents can trust NGFW)

  1. Objects → PKI → CA Certificates → select your intercept CA
  2. Click Export → download PEM
  3. Install on cluster: kubectl create configmap ngfw-ca -n web-agents --from-file=ngfw-ca.crt=<file>.pem

Step 3: Create SSL Policy

  1. Policies → SSL → New Policy
  2. Name: DUT-TLS-Inspection
  3. Add rule:
  4. Action: Decrypt — Resign
  5. Source Zones: agents
  6. Destination Zones: personas
  7. Destination Ports: TCP 443, UDP 443
  8. Resign CA: select your intercept CA
  9. Default Action: Do Not Decrypt (pass through other traffic)

Step 4: Create Access Control Policy rule

  1. Policies → Access Control → your policy
  2. Add rule above the default:
  3. Source Networks: 172.16.0.0/16, 172.17.0.0/16
  4. Destination Networks: 10.1.0.0/16
  5. Destination Ports: TCP 443, UDP 443
  6. SSL Policy: DUT-TLS-Inspection
  7. Action: Allow (with inspection)
  8. Intrusion Policy: attach if you want IPS metrics during the test
  9. Deploy to the FTD sensor

Step 5: Configure interfaces

# In FMC: Devices → Device Management → select your FTD → Interfaces
# Set up subinterfaces on the physical interfaces:

Inside interface (trunk):
  Subinterface 20: VLAN 20, IP 172.16.0.1/16, Security Zone: agents
  Subinterface 30: VLAN 30, IP 172.17.0.1/16, Security Zone: agents

Outside interface (trunk):
  Subinterface 101: VLAN 101, IP 10.1.1.1/27,  Security Zone: personas
  Subinterface 102: VLAN 102, IP 10.1.2.1/27,  Security Zone: personas
  ...
  Subinterface 120: VLAN 120, IP 10.1.20.1/27, Security Zone: personas

Management interface:
  Subinterface 99: VLAN 99, IP 100.127.252.3/24  (out-of-band, SNMP)

8.2 Cisco FTD — Firepower Device Manager

Import persona-ca

  1. Objects → Certificates → Trusted CA → Add
  2. Name: Persona-CA, upload persona-ca.pem

Export ngfw-ca

  1. Policies → SSL → Trusted CA → export your intercept CA

Create SSL Decryption Policy

  1. Policies → SSL Decryption → Add Rule
  2. Source: 172.16.0.0/16, 172.17.0.0/16
  3. Destination: 10.1.0.0/16
  4. Port: HTTPS (443/tcp)
  5. Action: Decrypt — Resign with your intercept CA

8.3 Cisco ASA

ASA with FirePOWER Services (SFR module) or ASA with AnyConnect SSL inspection:

# Import persona-ca as trusted CA
crypto ca authenticate DUT-ROOT-CA

# Paste the PEM content when prompted (the persona-ca.pem contents)

# Create crypto map or SSL inspection policy targeting:
#   src 172.16.0.0 255.255.0.0 and 172.17.0.0 255.255.0.0
#   dst 10.1.0.0 255.255.0.0
#   port 443

# Create subinterfaces for agent VLANs
interface GigabitEthernet0/0.20
 encapsulation dot1Q 20
 ip address 172.16.0.1 255.255.0.0
 nameif agents-pw
 security-level 50

interface GigabitEthernet0/0.30
 encapsulation dot1Q 30
 ip address 172.17.0.1 255.255.0.0
 nameif agents-k6
 security-level 50

# Create subinterfaces for persona VLANs (repeat for 101-120)
interface GigabitEthernet0/1.101
 encapsulation dot1Q 101
 ip address 10.1.1.1 255.255.255.224
 nameif persona-shop
 security-level 0

# ... repeat for VLANs 102-120 ...

# Enable SSL inspection via FirePOWER module or ASA CX

8.4 FortiGate

Create VLANs and interface IPs

# In CLI:
config system interface
  edit "inside.20"
    set vdom "root"
    set ip 172.16.0.1 255.255.0.0
    set allowaccess ping
    set type vlan
    set interface "port1"
    set vlanid 20
    set role lan
  next
  edit "inside.30"
    set vdom "root"
    set ip 172.17.0.1 255.255.0.0
    set type vlan
    set interface "port1"
    set vlanid 30
    set role lan
  next
  edit "outside.101"
    set vdom "root"
    set ip 10.1.1.1 255.255.255.224
    set type vlan
    set interface "port2"
    set vlanid 101
    set role wan
  next
  # ... repeat for VLANs 102-120 ...
end

Import persona-ca

# GUI: Security Profiles → SSL/SSH Inspection → Create/Edit profile
# Under "CA Certificate": import persona-ca.pem

# Or via CLI:
config vpn certificate ca
  edit "Persona-CA"
    set ca "<base64-encoded-persona-ca>"
  next
end

Export ngfw-ca

# GUI: Security Profiles → SSL/SSH Inspection → select your profile
#       → CA Certificate → Download
# This downloads the FortiGate's intercept CA in PEM format.

Create SSL/SSH Inspection Profile

# GUI: Security Profiles → SSL/SSH Inspection → Create New
config firewall ssl-ssh-profile
  edit "DUT-Inspection"
    set comment "TLSStress.Art DUT mode"
    config https
      set ports 443
      set status deep-inspection
      set proxy-after-tcp-handshake enable
    end
    config ssl
      set inspect-all deep-inspection
    end
    set caname "Persona-CA"
  next
end

Create firewall policy

config firewall policy
  edit 100
    set name "DUT-agents-to-personas"
    set srcintf "inside.20" "inside.30"
    set dstintf "outside.101" "outside.102" ... "outside.120"
    set srcaddr "172.16.0.0/16" "172.17.0.0/16"
    set dstaddr "10.1.0.0/16"
    set action accept
    set schedule "always"
    set service "HTTPS"
    set ssl-ssh-profile "DUT-Inspection"
    set utm-status enable
    set logtraffic all
  next
end

8.5 Palo Alto PAN-OS

Import persona-ca

# GUI: Device → Certificate Management → Certificates → Import
# Name: Persona-CA
# File: persona-ca.pem
# Mark as: "Trusted Root CA"

# Or via CLI:
scp import certificate from <user@host:/path/persona-ca.pem>
> certificate-name Persona-CA
> category trusted-root-CA

Export ngfw-ca

# GUI: Device → Certificate Management → Certificates →
#       select your forward-trust certificate → Export Certificate
# Format: Base64 Encoded Certificate (PEM)

Create interfaces

# GUI: Network → Interfaces → Ethernet → Add Sub-Interface

# Inside interface (toward agents)
Ethernet1/1.20:  IP 172.16.0.1/16, VLAN 20, Zone: agents
Ethernet1/1.30:  IP 172.17.0.1/16, VLAN 30, Zone: agents

# Outside interface (toward personas)
Ethernet1/2.101: IP 10.1.1.1/27,   VLAN 101, Zone: personas
Ethernet1/2.102: IP 10.1.2.1/27,   VLAN 102, Zone: personas
# ... repeat for 103-120 ...

Create Decryption Profile

# GUI: Objects → Decryption Profile → Add
# Name: DUT-Decrypt-Profile
# SSL Forward Proxy:
#   Forward Trust Certificate: <your intercept CA>
#   Forward Untrust Certificate: <your untrust CA>
# Server Certificate Verification:
#   Block sessions with expired certificates: yes
#   Block sessions with untrusted issuers: yes (with persona-ca as trusted)

Create Decryption Policy

# GUI: Policies → Decryption → Add
# Name: DUT-Decrypt-All
# Source Zone: agents
# Destination Zone: personas
# Source Address: 172.16.0.0/16, 172.17.0.0/16
# Destination Address: 10.1.0.0/16
# Service: application-default (or create HTTPS service for 443/tcp + 443/udp)
# Type: SSL Forward Proxy
# Profile: DUT-Decrypt-Profile

Create Security Policy

# GUI: Policies → Security → Add
# Name: agents-to-personas
# Source Zone: agents
# Destination Zone: personas
# Application: ssl, web-browsing
# Service: application-default
# Action: Allow
# Profile Group: attach your threat/URL profile

8.6 Check Point

Import persona-ca

# SmartConsole → Objects → New → Certificate Authority → Trusted CA
# Name: Persona-CA
# Upload: persona-ca.pem

Export ngfw-ca

# SmartConsole → Gateways & Servers → double-click your gateway
# → HTTPS Inspection → CA Certificate → Export
# Save as PEM

Configure HTTPS Inspection

# SmartConsole → Security Policies → HTTPS Inspection → Policy
# Add rule:
# Name: DUT-Inspection
# Source: Group(172.16.0.0/16, 172.17.0.0/16)
# Destination: Group(<20 country /24 prefixes from §3.3 — VLANs 101-120>)
# Services: HTTPS (443)
# Site Category: Any
# Action: Inspect
# Track: Log

# Under Blade Control → SSL Inspection → Trusted CA:
# Add Persona-CA to the trusted store

Configure interfaces

# SmartConsole → Gateways → Interfaces → Add VLAN
# Create sub-interfaces for each VLAN (20, 30, 101-120)
# Assign IPs per section 3 above

9. Verification

9.1 Verify connectivity from the cluster

# SSH into one of the agent pods
kubectl exec -it -n web-agents deployment/web-agent -- sh

# Test that the NGFW gateway is reachable
ping -c 3 172.16.0.1        # browser-engine VLAN 20 gateway
ping -c 3 172.17.0.1        # K6 VLAN 30 gateway (from K6 pod)

# Test HTTPS to a persona (should succeed if TLS inspection is working)
curl -v https://shop.persona.internal/ --max-time 5
# Expected: HTTP 200, certificate issued by NGFW CA

9.2 Verify TLS inspection is active

# From an agent pod, inspect the certificate chain presented by the NGFW
echo | openssl s_client -connect shop.persona.internal:443 -servername shop.persona.internal 2>/dev/null \
  | openssl x509 -noout -issuer -subject

# Expected output (certificate issued by NGFW, not by persona-ca):
# issuer=CN=<your NGFW intercept CA name>
# subject=CN=shop.persona.internal   (re-signed by NGFW)

9.3 Verify SNMP monitoring

# From the SNMP pod, test connectivity to the NGFW
kubectl exec -it -n web-agents deployment/snmp-exporter -- sh
snmpwalk -v2c -c <community> 100.127.252.3 1.3.6.1.2.1.1.1.0

# Expected: sysDescr of the NGFW

9.4 Verify TLS Leg 2 (NGFW trusts webserver cert)

Check NGFW logs for TLS errors on the outbound leg. If you see certificate validation failures toward 10.1.x.x (Synthetic Personas) or 10.2.x.x (Cloned Personas), the persona-ca was not imported correctly.

# On the cluster: confirm the webserver certificate chain
echo | openssl s_client -connect 10.1.1.2:443 2>/dev/null \
  | openssl x509 -noout -issuer -subject

# Expected (before NGFW interception — direct from Ubuntu server):
# issuer=CN=Persona CA  (or similar — the persona-ca-issuer CN)
# subject=CN=shop.persona.internal

10. Troubleshooting

Symptom Likely cause Fix
Agents get CERT_AUTHORITY_INVALID ngfw-ca not installed in cluster, or agents not restarted Re-run kubectl create configmap ngfw-ca ... and kubectl rollout restart deployment/web-agent
NGFW shows TLS Leg 2 cert validation error persona-ca not imported in NGFW trust store Export persona-ca.pem from cluster (kubectl get secret persona-ca-bundle ...) and import in NGFW trusted CA store
HTTP/3 connections fail but HTTP/2 works NGFW doesn't support QUIC inspection Block UDP 443 on NGFW to force HTTP/2 downgrade; note this in test results
Agents can't reach persona IPs (10.1.x.x) Missing routes or NGFW policy blocking Check NGFW security policy allows 172.16.0.0/16 and 172.17.0.0/16 to 10.1.0.0/16
SNMP exporter shows no data from NGFW NGFW SNMP not enabled, wrong community, or VLAN 99 not reachable Verify NGFW SNMP is enabled with community public (or matching observability/snmp/snmp.yml); verify VLAN 99 IP 100.127.252.3 is pingable
TLS inspection not triggered SSL policy not attached to access rule, or zones misconfigured Verify source/destination zones match agent and persona interfaces
Certificate errors after persona cert renewal NGFW cached old cert fingerprint Cert-manager auto-renews persona certs every 11 months; Stakater Reloader restarts Caddy pods — no NGFW change needed

For test-bed architecture details, see docs/ARCHITECTURE.md. For deployment instructions, see docs/UBUNTU_K3S_SINGLENODE_QUICKSTART_DEPLOY.md. For the automated Kubernetes installer, see scripts/k8s-install.sh.