Skip to content

AWS lab — from scratch to live traffic

A complete, click-by-click lab guide. It takes you from nothing in AWS to a working Enforza firewall that is enrolled in the Cloud Controller (CCX) console, enforcing a policy, and showing you live traffic.

Every step has an [Explanation] of what you’re doing and why, written for semi-technical people — you don’t need to be a network engineer.

An Internet Gateway connects the VPC to the internet; the public subnet holds the Enforza firewall EC2 (source/dest check off, public IP), which enrols with the Enforza Cloud Controller; the private subnet holds a workload EC2 with no public IP, whose route table sends 0.0.0.0/0 to the firewall’s ENI — so all its traffic is forced through the firewall for inspection.

Editable topology diagram (open in draw.io / diagrams.net): aws-lab-topology.drawio.

Before you start

  • An AWS account and permission to create VPC/EC2 resources.
  • An Enforza console login (CCX) with at least 1 free engine licence.
  • An SSH key pair (you’ll create or reuse one at launch).
  • ~20 minutes. Cost: a t3.small is a few pence/hour — terminate it when done.
  • Region: this guide uses eu-west-2 (London); any region works, just stay consistent.

Console: VPC → Your VPCsCreate VPC → choose VPC only

  • Name: enforza-lab
  • IPv4 CIDR: 10.10.0.0/16
  • Leave IPv6 off, tenancy default → Create VPC.

[Explanation] A VPC is your own private, isolated network inside AWS — think of it as the “building” all your lab machines live in. The CIDR 10.10.0.0/16 is the pool of private IP addresses available inside it (65k addresses). Nothing here is reachable from the internet yet; we add that next.

Console: VPC → SubnetsCreate subnet

  • VPC: enforza-lab
  • Name: enforza-lab-public
  • Availability Zone: pick one, e.g. eu-west-2a
  • IPv4 CIDR: 10.10.1.0/24Create subnet.

[Explanation] A subnet is a slice of the VPC’s addresses pinned to one Availability Zone (one physical data-centre area). We’ll put the firewall here. It’s called “public” only because in Step 4 we give it a route to the internet — a subnet isn’t public until its route table says so.

Step 3 — Create and attach an Internet Gateway

Section titled “Step 3 — Create and attach an Internet Gateway”

Console: VPC → Internet gatewaysCreate internet gateway → name enforza-lab-igwCreate. Then Actions → Attach to VPC → select enforza-labAttach.

[Explanation] An Internet Gateway (IGW) is the door between your VPC and the public internet. Creating it isn’t enough — you must attach it to the VPC, and then (next step) tell the subnet’s route table to use it. The firewall needs internet access so it can reach the Enforza control plane to enrol.

Step 4 — Route the subnet to the internet

Section titled “Step 4 — Route the subnet to the internet”

Console: VPC → Route tablesCreate route table

  • Name: enforza-lab-public-rt, VPC: enforza-labCreate.

Then on that route table:

  1. Routes tab → Edit routesAdd route:
    • Destination 0.0.0.0/0, Target Internet Gatewayenforza-lab-igwSave changes.
  2. Subnet associations tab → Edit subnet associations → tick enforza-lab-publicSave.

[Explanation] A route table is the signpost that tells traffic where to go. The 0.0.0.0/0 route means “anything not local to the VPC → send to the internet gateway”. Associating it with the public subnet is what actually makes that subnet “public”. Without this, your firewall would launch but never be able to phone home to Enforza.

Step 5 — Create a wide-open security group (lab only)

Section titled “Step 5 — Create a wide-open security group (lab only)”

Console: VPC (or EC2) → Security groupsCreate security group

  • Name: enforza-lab-any, VPC: enforza-lab
  • Inbound rules → Add rule: Type All traffic, Source Anywhere-IPv4 (0.0.0.0/0)
  • Outbound rules: leave the default All traffic → 0.0.0.0/0
  • Create security group.

[Explanation] A security group (AWS’s equivalent of an NSG) is a stateful firewall around the instance’s network card. We open it any/any so it never gets in the way while you’re learning — that way, the only thing filtering traffic is Enforza itself, which is the whole point of the lab. Never do this in production — there you’d lock inbound down to just your admin IP. Note that even wide-open, AWS security groups only allow; the Enforza engine is what gives you deny and hostname rules.

Part 2 — Launch the firewall EC2 instance

Section titled “Part 2 — Launch the firewall EC2 instance”

Console: EC2 → InstancesLaunch instances

  • Name: enforza-fw-lab
  • AMI: Ubuntu Server 22.04 LTS (what Enforza tests against; Debian/RHEL/Rocky/ Amazon Linux 2023 also work)
  • Instance type: t3.small (fine for a lab — 2 vCPU / 2 GiB)
  • Key pair: select an existing one, or Create new key pair (download the .pem — you’ll need it to SSH)
  • Network settings → Edit:
    • VPC: enforza-lab
    • Subnet: enforza-lab-public
    • Auto-assign public IP: Enable
    • Firewall (security groups): Select existingenforza-lab-any
  • Launch instance. Note the Instance ID and, once running, its Public IPv4 address.

[Explanation] This EC2 instance is the Enforza firewall — the engine is a single Linux daemon we’ll install on it in Part 3. Auto-assign public IP is essential: it’s how the box reaches the internet (via the IGW + route table you just built) to enrol and stream logs. The key pair is your SSH login. We picked a small size because a lab pushes tiny traffic; the engine auto-tunes to bigger instances when you need throughput.

Step 7 — Turn off the source/destination check ⚠️ critical

Section titled “Step 7 — Turn off the source/destination check ⚠️ critical”

Console: EC2 → Instances → select enforza-fw-labActions → Networking → Change source/destination check → tick Stop (uncheck the enabled box) → Save.

(CLI equivalent, region eu-west-2:)

Terminal window
aws ec2 modify-network-interface-attribute --region eu-west-2 \
--network-interface-id <eni-of-the-instance> --no-source-dest-check

[Explanation] By default AWS drops any packet whose destination isn’t the instance’s own IP address. But a firewall’s entire job is to handle packets meant for other machines. So this AWS safety check must be off, or the firewall will silently blackhole every forwarded packet. This is the single most common “it’s installed but nothing works” mistake. In a lab where the box only filters its own traffic you can get away without it, but turn it off now so Part 7 (routing a workload through it) just works.

Part 3 — Enrol the engine with the console

Section titled “Part 3 — Enrol the engine with the console”

Console (CCX): sidebar → Onboard FirewallDeployment Keys tab → Generate key. Choose:

  • Single-use — binds exactly one firewall (use this for the lab), or
  • Provisioning — reusable across a fleet (Terraform/Ansible/CI).

Copy the install command it shows you — it looks like:

Terminal window
curl -fsSL https://dl.neon.efz.io/install.sh \
| sudo bash -s -- --regkey=YOUR-KEY-HERE

[Explanation] The deployment key is a one-time token that lets this firewall prove to the Enforza cloud “I’m allowed to join your account.” The install command downloads the engine installer and passes the key to it. A single-use key is consumed by the first engine that uses it — so mint one key per firewall. (There’s also a Cloud Claim tab for AWS Marketplace instances that self-register — ignore it for a manual lab install.)

Step 9 — SSH in and run the install command

Section titled “Step 9 — SSH in and run the install command”

From your laptop (use the .pem from Step 6 and the instance’s public IP):

Terminal window
chmod 400 enforza-lab.pem # first time only
ssh -i enforza-lab.pem ubuntu@<PUBLIC-IP>

Then paste the copied install command and press Enter:

Terminal window
curl -fsSL https://dl.neon.efz.io/install.sh \
| sudo bash -s -- --regkey=YOUR-KEY-HERE

[Explanation] SSH is a secure remote terminal into the box. The installer (~30–60 s) detects your Linux distro, installs prerequisites, fetches the engine binary, swaps your one-time key for a long-lived licence token, and starts the enforza-engine service. The username is ubuntu for the Ubuntu AMI (admin for Debian, ec2-user for Amazon Linux/RHEL).

On the VM:

Terminal window
systemctl status enforza-engine # should say: active (running)

In the console: sidebar → Firewalls — your new engine appears with status Online within ~10 seconds of the install finishing.

[Explanation] “Online” means the engine has enrolled and opened its always-on WebSocket back to the Enforza cloud. That control channel is how the cloud pushes policy and how the engine streams logs — and it bypasses policy by design, so you can never accidentally lock the engine away from its own management plane. If it never shows up, the box has no internet path — re-check the IGW, route table, and public IP (Part 1 + Step 6).

Enforza policies have three sections, which map exactly onto the classic firewall chains you may know as input / forward / output:

Enforza sectionClassic nameWhat it controls
to-firewallINPUTTraffic addressed to the firewall box itself (e.g. SSH to it)
through-firewallFORWARDTraffic passing through the firewall between other hosts — the main event
from-firewallOUTPUTTraffic the firewall box originates itself (DNS, NTP, updates)

[Explanation] Every policy is built in the console — no YAML editing. Each section has its own default action; we’ll set them to drop (fail-closed: if nothing explicitly allows a packet, it’s denied). Nothing reaches the firewall until you Push — saving a draft is safe.

Console: sidebar → PoliciesNew policy

  • Name: lab-policy
  • Default action: dropCreate.

[Explanation] This creates an empty policy with a deny-by-default posture. From here we add just enough “allow” rules to keep things working, then one “deny” rule to prove filtering works.

Step 12 — from-firewall (OUTPUT): let the engine’s OS reach out

Section titled “Step 12 — from-firewall (OUTPUT): let the engine’s OS reach out”

Open the Local tab (from-firewall) → Add rule for each:

CommentDestinationProtocolPortAction
dnsanyudp/tcp53Accept
ntpanyudp123Accept
httpsanytcp443Accept

[Explanation] These let the firewall’s own operating system do housekeeping — resolve names (DNS), keep its clock right (NTP), and fetch updates (HTTPS). Everything the engine needs to reach the Enforza cloud already bypasses policy, so the box won’t brick without these — but OS services start failing, so it’s good hygiene to allow them.

Step 13 — to-firewall (INPUT): keep your SSH, drop the rest

Section titled “Step 13 — to-firewall (INPUT): keep your SSH, drop the rest”

Open the Management tab (to-firewall) → Add rule:

CommentSourceProtocolPortAction
allow my ssh<your-laptop-public-IP>/32tcp22Accept

Leave the section default action = drop.

[Explanation] This section guards the firewall box itself. We explicitly allow SSH only from your IP so you keep your terminal, and drop everything else aimed at the box. ⚠️ If you skip the SSH allow and set default drop, your next SSH attempt is blocked (the engine’s own cloud control channel keeps working — only your SSH is affected). Find your public IP at https://ifconfig.me. Note: hostname/URL rules are not allowed in this section — inbound-to-the-box traffic is matched on IP/port only.

Step 14 — through-firewall (FORWARD): the actual traffic inspection

Section titled “Step 14 — through-firewall (FORWARD): the actual traffic inspection”

Open the Network tab (through-firewall) → add two rules:

Rule 1 — allow web egress (start permissive):

CommentSourceDestinationProtocolPortAction
web egressanyanytcp443Accept

Rule 2 — block SSH crossing the firewall, and log it:

CommentSourceDestinationProtocolPortActionFlags
block fwd sshanyanytcp22Droptick Log

Then Save.

[Explanation] This is the section that inspects traffic passing through the firewall — the real product. We allow HTTPS so normal web traffic flows, and we drop + log SSH so you have something visibly blocked to watch in the live logs later. Rules are first-match-wins within a section — drag the row handle to reorder. Ticking Log is what makes a matched flow show up in Live Traffic. Want hostname filtering (like github.com subdomains) instead of IP/port? Switch the rule type to URL Filtering and match on the SNI hostname.

From the policy editor toolbar → Push. The publish dialog runs preflight checks (schema + any guardrails), then publishes.

[Explanation] Push is the moment your draft becomes a real, versioned policy in the cloud — but it’s still not enforcing on any firewall yet. Publishing and binding (next) are two separate steps on purpose: you can prepare a policy safely without touching a live box. Tip: Download policy first if you want to eyeball the generated YAML.

Part 5 — Bind the policy to your firewall

Section titled “Part 5 — Bind the policy to your firewall”

Console: sidebar → Bindings → find your enforza-fw-lab row (it shows Unbound) → Apply policy → pick lab-policyConfirm.

[Explanation] Publishing made the policy available; the binding is what actually wires this firewall to this policy. A brand-new engine is Unbound — it enforces nothing and drops nothing until you bind. The engine notices the change on its next config poll (within ~5 seconds) and applies it.

Console: sidebar → Firewalls. Your firewall row now shows the policy name and a green Synced chip with the active policy’s SHA.

(Optional, on the VM:)

Terminal window
sudo nft list ruleset | head -40 # your rules appear in the enforza-fwd table

[Explanation] The green Synced chip means the engine successfully downloaded, compiled, and loaded your policy into the Linux kernel. If instead you see a red Parse / Compile / Apply error chip, it carries the engine’s own error message — fix the rule and Push again. The nft command is bare-metal proof the rules are live in the kernel.

Console: Firewalls → click your firewall → Live logs tab. (Or sidebar → Live Traffic to stream one or several firewalls together.)

Generate some traffic to see it: SSH into the box and run

Terminal window
curl -sI https://example.com # should succeed → accept on TCP/443

[Explanation] Every accept / drop / flow-close on the engine streams to the console over the WebSocket only while a viewer is open (to keep costs bounded; each session caps at 15 minutes — just reload to continue). New events appear at the top. Pause to inspect, Resume to catch up, Clear to wipe the on-screen buffer.

Columns: Time · Flow · Action · Proto · Source · Destination · SNAT · Hostname · Rule. Click any row for the full JSON detail (Event / Network / GeoIP / Packet / TLS / Flow / Engine).

  • Action — accept (green) / drop (red)
  • Proto — e.g. TCP/443
  • Hostname — the TLS SNI / HTTP Host the engine extracted (URL rules only)
  • Rule — the comment of the rule that matched (that’s why good comments matter)
  • Filter box — matches across IP, port, hostname, rule name, country, ASN.

[Explanation] This closes the whole loop: you can literally watch your web egress rule turn a request green and — if you try to SSH through the box — your block fwd ssh rule turn it red. The Rule column tells you exactly which line of policy decided each packet, which is how you debug a policy in seconds instead of guessing.

For “what happened earlier”, use the firewall’s Search logs tab: pick a time range (up to 7 days) and filter by action, protocol, IP, port, Hostname / SNI, or free text.

[Explanation] Live logs only show new events. Search logs queries the engine’s own on-disk history — nothing is stored in the cloud by default, so your traffic data stays on your VM unless you set up Log Export (S3 / Splunk / Sentinel) under Configure → Log Export.

Part 7 — Route a real workload through the firewall

Section titled “Part 7 — Route a real workload through the firewall”

Parts 1–6 filter the firewall box’s own traffic. To see the through-firewall section really work, add a private subnet with a second “workload” EC2 whose only way out is through the firewall. Then you watch the workload’s real internet traffic appear in the firewall’s live logs.

Console: VPC → SubnetsCreate subnet

  • VPC: enforza-lab, Name: enforza-lab-private
  • Same AZ as the firewall (e.g. eu-west-2a)
  • IPv4 CIDR: 10.10.2.0/24Create subnet.

[Explanation] This subnet has no route to the Internet Gateway — that’s deliberate. A machine here can’t reach the internet on its own; we’ll force its traffic through the firewall instead. That’s what makes the inspection real: the workload literally cannot bypass the firewall.

Step 22 — Find the firewall’s network interface (ENI)

Section titled “Step 22 — Find the firewall’s network interface (ENI)”

Console: EC2 → Instancesenforza-fw-labNetworking tab → Network interfaces → note the Interface ID (eni-…).

[Explanation] The ENI is the firewall’s virtual network card. We’ll point the workload’s default route at this specific card so all its traffic lands on the firewall.

Step 23 — Route the private subnet through the firewall ENI

Section titled “Step 23 — Route the private subnet through the firewall ENI”

Console: VPC → Route tablesCreate route table

  • Name: enforza-lab-private-rt, VPC: enforza-labCreate.

Then:

  1. Routes tab → Edit routesAdd route: Destination 0.0.0.0/0, Target Network Interface → select the firewall’s eni-…Save changes.
  2. Subnet associations tab → Edit → tick enforza-lab-privateSave.

[Explanation] This is the heart of the inspection pattern. The private subnet’s default route now says “anything bound for the internet → hand it to the firewall’s ENI.” The firewall inspects it against your through-firewall rules, then source-NATs (SNAT) it out through its own public path. Remember Step 7: if the firewall’s source/dest check were still on, AWS would drop these forwarded packets — that’s why we turned it off up front.

Step 24 — Launch the workload EC2 in the private subnet

Section titled “Step 24 — Launch the workload EC2 in the private subnet”

Console: EC2 → Launch instances

  • Name: enforza-workload-lab, same Ubuntu AMI, t3.small
  • Network settings → Edit: VPC enforza-lab, Subnet enforza-lab-private, Auto-assign public IP: Disable, Security group enforza-lab-any
  • Same key pair → Launch.

[Explanation] This is the “customer” machine sitting behind the firewall. It has no public IP, so its only path to the internet is the route you just made — through the firewall. To get a terminal on it (it’s not directly reachable), either use it as-is via AWS Systems Manager → Session Manager, or SSH to it from the firewall box as a jump host (ssh ubuntu@10.10.2.x from inside the firewall). Session Manager works because the workload’s outbound 443 now flows out through the firewall, which your web egress rule allows.

Step 25 — Generate traffic and watch it on the firewall

Section titled “Step 25 — Generate traffic and watch it on the firewall”
  1. In the console, open Firewalls → enforza-fw-lab → Live logs (leave it running).
  2. On the workload box, generate some traffic:
    Terminal window
    curl -sI https://example.com # allowed → accept on TCP/443
    nc -vz somehost 22 # crosses the firewall → your block-fwd-ssh Drop fires
  3. Watch the rows appear on the firewall’s live log — the workload’s private IP (10.10.2.x) as Source, the Rule column naming which policy line decided each flow, and the SNAT column green as the firewall translates the traffic on the way out.

[Explanation] This closes the loop end-to-end: a real machine’s traffic is now being forced through your firewall, inspected against the through-firewall rules, and shown to you live with the deciding rule named. The workload has no direct internet path, so all its outbound traffic must cross the firewall — this is the real inspection pattern. Change a rule, Push, re-run the curl, and watch the verdict flip: the full authoring-to-observation cycle in seconds.

SymptomMost likely cause
Install exits registration key not foundKey already consumed or expired — mint a fresh one (Onboard Firewall → Deployment Keys).
Engine installs but never appears in consoleNo outbound internet — check IGW attached, route table 0.0.0.0/0 → IGW, subnet association, and Auto-assign public IP.
Firewall shows red Apply/Compile error chipPolicy rejected by the engine — read the inline error, fix the rule, Push again.
Traffic through the box is dropped unexpectedlySource/dest check still on (Step 7), or a section default-drop with no matching allow.
You got locked out of SSHto-firewall default-drop with no allow my ssh rule — fix via AWS Session Manager or relax the rule and re-push.
Nothing in Live logsNo viewer was open when traffic flowed, the flow didn’t match a Log-ticked rule, or no traffic was generated.

When you’re done: EC2 → Instances → select enforza-fw-labTerminate. Then delete the workload instance (if any), the security group, subnets, route tables, IGW, and the VPC. In the console, the firewall drops to Offline; remove it from Firewalls if you won’t reuse it.

[Explanation] A running t3.small costs a few pence per hour; terminating stops all charges. Tearing the VPC down keeps your account tidy. Your deployment key was single-use and is already spent — mint a new one next time.

  1. Network: VPC → public subnet → IGW → route 0.0.0.0/0 → IGW → any/any SG.
  2. Instance: launch in public subnet, public IP on, source/dest check OFF.
  3. Enrol: Onboard Firewall → Deployment Key → SSH → paste install command → Online.
  4. Policy: drop default, allow OS egress (from-firewall), guard SSH (to-firewall), inspect + block (through-firewall) → Push.
  5. Bind: Bindings → Apply policy → Synced.
  6. Observe: Firewalls → Live logs (and Search logs for history).

Enforza is a trading name of Synvu Limited, a company registered (15761962) in the United Kingdom. Registered office address: 71–75 Shelton Street, Covent Garden, London, WC2H 9JQ, United Kingdom.