Three of the five findings in the previous pentest were, at bottom, network problems: a panel published on the host's external interface, a subdomain pointing at somebody else's IP and a service reachable from where it should not be. And the three big ones have been outstanding since 05-01: PostgreSQL listening on 0.0.0.0:5432, SSH open to the whole Internet and the consultancy with permanent access. This lesson draws Nimbus's network as it stands, redesigns it into zones, closes those holes, sets up remote access and DNS the way they should be, and finishes by checking with connectivity tests that the segmentation really works: an untested design is just a pretty drawing.

Contents

  1. Nimbus's network today, with its problems
  2. Segmentation: the control with the best cost/impact ratio
  3. Firewalls: types, default policy and egress rules
  4. Secure remote access: VPN, bastion host and just-in-time access
  5. Corporate and guest wifi
  6. DNS: resolution, filtering and protecting the domain
  7. Protection against DoS and DDoS
  8. Network detection and the problem of encrypted traffic
  9. Zero Trust applied to the network
  10. Verifying that the segmentation works

  1. Nimbus's network today, with its problems

flowchart TB
    subgraph OF["VALENCIA OFFICE - 10.20.0.0/16"]
      direction LR
      W1["Corporate wifi\n40 laptops"] --- SW["Flat switch\nONE SINGLE VLAN"]
      W2["Guest wifi\n(same physical network)"] --- SW
      NAS["NAS and copier\nwith no password"] --- SW
      AP["Access points\nand router: web panel\nwith default password"] --- SW
    end
    subgraph REM["REMOTE WORKING - 20 people"]
      P["Laptops at home,\ncoworking, public wifi"]
    end
    subgraph CL["CLOUD - 10.30.0.0/16"]
      API["FastAPI API\n10.30.10.11-12"]
      DB["PostgreSQL\n10.30.20.5\nPORT 5432 OPEN TO 0.0.0.0/0"]
      S3["Bucket A-02 attachments\nand A-03 backups"]
      PRE["PREPRODUCTION A-22\n10.30.90.7\nRedis and http.server open"]
    end
    SW -->|"SSH open to 0.0.0.0/0"| API
    P -->|"direct connection\nno VPN"| API
    API --> DB
    API --> S3
    PRE -->|"credentials shared\nwith production"| DB
    CONS["CONSULTANCY A-19\nPERMANENT remote access\nshared account, no MFA"] --> API
    CONS --> DB

Seven problems, ordered by severity:

# Problem Direct consequence
1 PostgreSQL on 0.0.0.0:5432 R-03. Anyone on the Internet can try to authenticate against 40 clinics' data
2 SSH open to 0.0.0.0/0 A permanent brute-force surface and 82 % of the alert noise from 05-02
3 Permanent access for the consultancy (A-19) The door the ransomware in 02-06 came through
4 Flat office network From a compromised laptop everything is reachable: it is the Target pattern
5 Guests on the same physical network Any visitor is inside the perimeter
6 Preproduction with access to the production database The finding from the threat hunt in 05-02
7 Remote working with no VPN and no source control Half the staff connect from wifi networks Nimbus does not control

None of them requires buying anything to fix. All seven are configuration, and that is the best news in the lesson.


  1. Segmentation: the control with the best cost/impact ratio

Segmentation divides the network into zones and explicitly controls what can talk to what. It is the control with the best cost/impact ratio because it does not prevent the intrusion, but it prevents the intrusion from becoming a catastrophe: it turns "they compromised a laptop" into "they compromised a laptop", and not into "they compromised the company".

It is the lesson of Target (02-06): the attackers came in through the air-conditioning supplier and reached the payment terminals because there was no boundary between the two. And it is also days 1-4 of the Nimbus incident: the data zone was reachable from the administration network with no intermediate control at all.

Minimum vocabulary. A VLAN separates broadcast domains on the same physical switch (it is logical, not new cabling); a subnet is the IP range associated with it; traffic between VLANs passes through a device that routes it and that is where the policy is applied. In the cloud the equivalents are the VPC subnets and the security groups, which are per-instance firewalls rather than perimeter ones: that enables microsegmentation, meaning two servers in the same subnet cannot talk to each other if they should not.

Target design for the office:

VLAN Zone Range May talk to
10 Users (laptops) 10.20.10.0/24 The Internet and the corporate VPN. Nothing in management or servers
20 Local servers (NAS, printing) 10.20.20.0/24 Only specific ports from VLAN 10
30 Guests 10.20.30.0/24 The Internet only, with client isolation
40 Management (switches, APs, router) 10.20.40.0/24 Only from Lucía's laptop, over the VPN or the console
50 Untrusted (IoT, meeting-room TV) 10.20.50.0/24 The Internet only

And in the cloud:

Subnet Contents Ingress allowed
10.30.1.0/24 public Load balancer and bastion host 443 from the Internet; 22 only from the VPN
10.30.10.0/24 private, application Containerised API 8000 only from the load balancer; 22 only from the bastion host
10.30.20.0/24 private, data PostgreSQL 5432 only from 10.30.10.0/24
10.30.90.0/24 preproduction A-22 Completely isolated from the three above

Fixing the two historical holes is literally this: 5432 stops accepting 0.0.0.0/0 and only accepts the application subnet; 22 stops accepting 0.0.0.0/0 on every server and is reachable only from the bastion host, which in turn is reachable only from the VPN. Twenty minutes of work for the highest-scoring risk in the register from 04-01.


  1. Firewalls: types, default policy and egress rules

Type What it inspects Where it goes at Nimbus
Packet filtering Headers: IP, port, protocol Cloud security groups, nftables on each host
Stateful Also the state of the connection: it allows the response to what you initiated The office router and all of the above
Next-generation (NGFW) Application, user, content; usually integrates an IPS Optional for the office; expensive for the budget
WAF (web application) HTTP requests: injections, attack patterns In front of the API. It is no substitute for fixing the code (05-05)

Two principles govern the configuration. The first: a default policy of deny. Everything is closed and only what is justified is opened, with a comment saying why. A rule with no documented justification is a rule nobody will dare remove three years from now.

The second, the one almost nobody applies: filter the egress too. Almost every organisation controls what comes in and lets anything go out to anywhere. But the exfiltration of 1.2 TB in 02-06 and the command-and-control channel are outbound traffic. A database server does not need to browse the Internet.

#!/usr/sbin/nft -f
# /etc/nftables.conf for the database server (10.30.20.5)
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;   # DENY BY DEFAULT

    ct state established,related accept   # responses to what we initiated ourselves
    ct state invalid drop                 # packets out of context
    iif "lo" accept                       # loopback

    # 5432 ONLY from the application subnet. This is where R-03 dies.
    ip saddr 10.30.10.0/24 tcp dport 5432 accept

    # SSH ONLY from the bastion host, never from the Internet.
    ip saddr 10.30.1.10/32 tcp dport 22 accept

    # Metrics for Prometheus, only from the collector.
    ip saddr 10.30.10.20/32 tcp dport 9187 accept
  }

  chain output {
    type filter hook output priority 0; policy drop;  # DENY THE EGRESS TOO

    ct state established,related accept
    oif "lo" accept
    udp dport 53 ip daddr 10.30.0.2 accept    # the internal resolver only
    udp dport 123 accept                      # NTP: without time there is no correlation
    tcp dport 443 ip daddr @package_repos accept    # updates, bounded list
    tcp dport 443 ip daddr @backup_endpoint accept  # backups to bucket A-03

    # Everything else is dropped AND LOGGED: this log is the exfiltration and
    # command-and-control detection that was missing in 02-06.
    log prefix "EGRESS-BLOCKED " level warn
  }
}

In the cloud, the same policy expressed as security groups:

sg-data:
  description: "Production PostgreSQL (A-01)"
  ingress:
    - from: sg-app                # references THE GROUP, not an IP range:
      port: 5432                  # if the API scales, the rule remains valid
      proto: tcp
      reason: "API connections. Replaces 0.0.0.0/0 (R-03, 2026-04-07)"
    - from: sg-bastion
      port: 22
      reason: "Administration, only via the bastion host"
  egress:
    - to: s3-private-endpoint     # backup traffic that does NOT go out to the Internet
      port: 443
      reason: "Backups to A-03 over a private endpoint"
    # No 0.0.0.0/0 egress rule: the data server does not browse.

Referencing groups and not IP ranges is the most cost-effective best practice in the cloud: the rule stays correct when the API scales, is replaced or changes IP, and it expresses the intent ("the application talks to the data") instead of an accident of addressing.

What egress filtering really costs is the first week: dependencies nobody had documented turn up. That is exactly why it is worth doing, because those unknown dependencies are also the surface the attacker uses. It is deployed in logging mode first, the EGRESS-BLOCKED entries are read for two weeks, the legitimate ones are opened and only then is it enforced.


  1. Secure remote access: VPN, bastion host and just-in-time access

VPN with WireGuard

WireGuard is free, fast, fits into 4,000 lines of auditable code and its configuration fits on one screen.

# /etc/wireguard/wg0.conf - VPN server in the public subnet (10.30.1.20)
[Interface]
Address    = 10.90.0.1/24        # network exclusive to the VPN, distinct from everything else
ListenPort = 51820
PrivateKey = <server private key>
PostUp   = nft add rule inet filter forward iifname wg0 oifname eth0 accept
PostDown = nft flush chain inet filter forward

# Lucia (systems administration)
[Peer]
PublicKey  = <Lucia's public key>
AllowedIPs = 10.90.0.10/32       # ONE fixed IP per person: without this, the access
                                 # logs do not identify anybody

# Ivan (development): same VPN, different identity and different permissions downstream
[Peer]
PublicKey  = <Ivan's public key>
AllowedIPs = 10.90.0.11/32

Three decisions matter. One fixed IP per person turns firewall logs into real traceability. Authentication is by key, with no passwords to guess, but that requires a joining and leaving procedure: offboarding an employee includes deleting their [Peer], and if it is not on the exit checklist, the access outlives the person. And the VPN gives access to the network, not to the systems: being on the VPN must not be enough to get into the database; authentication is still required at each service.

SSH bastion host

# ~/.ssh/config on Lucia's laptop
Host bastion
    HostName 10.30.1.10
    User lucia
    IdentityFile ~/.ssh/id_ed25519_nimbus     # Ed25519 (03-06)
    IdentitiesOnly yes                        # do not offer every key

Host api-* db-*
    ProxyJump bastion             # hops through the bastion without leaving the key on it
    User lucia                    # It is not a manual tunnel: the private key NEVER
    IdentityFile ~/.ssh/id_ed25519_nimbus     # reaches the bastion host

ProxyJump is the key piece: the bastion host forwards the connection, but authentication happens end to end and the private key never touches the bastion. That is the difference from the old habit of copying the key to the jump host, which turns the bastion into a single point of total compromise. The bastion host also records every session and is the only host with 22 reachable, and only from the VPN.

Just-in-time access and the consultancy (A-19)

Just-in-time access inverts the model: instead of permanent access that is revoked when somebody remembers, there is no access until it is requested, approved and granted with automatic expiry. It is control C-03 from 04-03, and for A-19 the implementation agreed in 04-04 is:

  • Named accounts, one per consultancy technician. The shared svc-consultora is over: with no name there is no accountability and no possible investigation.
  • Mandatory MFA, the control that on its own would have prevented the incident.
  • A request with a ticket stating system, reason and duration; approval by Lucía or Marta.
  • An 8-hour expiry, enforced by the system and not by anybody's memory.
  • Access to the specific system only, not to the whole network.
  • Alert D-03 from 05-02 if an authentication appears outside the agreed window.
  • Revocation of the 2023 exception with no expiry date in the register from 04-02, which is what was keeping the permanent access alive.

  1. Corporate and guest wifi

WPA2-Personal WPA2-Enterprise WPA3
Authentication A key shared by everyone An individual credential (802.1X) Individual or SAE
If somebody leaves The key has to be changed for everyone Their account is deleted Same
Traffic capture With the key you can decrypt other people's No No: PFS per session
Offline dictionary attack Possible with a capture of the handshake No No (SAE prevents it)

For Nimbus: WPA3 where the hardware allows it and WPA2-Enterprise everywhere else, with an individual credential against the identity provider. The single key shared by 38 people is on dozens of phones, has been passed around in chats and has not changed since 2022.

The guest network must be genuinely isolated: its own VLAN 30, with no route to any other VLAN, client isolation switched on (so two guests cannot see each other), a bandwidth limit, a portal with terms of use and a rotated key. The usual mistake is using the same access point with a different SSID but no VLAN separation: that is the same network with two names.

Two things that are not controls, and it is worth saying so bluntly: MAC filtering — MAC addresses are cloned with one command and are visible over the air even when the traffic is encrypted — and hiding the SSID — the network still announces itself every time a client connects, and it also forces laptops to go around actively looking for it, which makes rogue access points easier. They consume administration time and give a false sense of security.

The risk of public wifi affects half the staff. Today TLS protects the content (03-05), so the classic "they read your password" scenario is largely historical; what is still real is the rogue access point impersonating a familiar portal and local DNS poisoning. The effective measure is simple and is already in place: an always-on VPN outside the office, with DNS forced through the tunnel, plus HSTS on all your own domains.


  1. DNS: resolution, filtering and protecting the domain

DNS is the cheapest control there is and the most forgotten. Three fronts:

Secure resolution and filtering. Every machine uses the corporate resolver (or the VPN tunnel's), never the one the café wifi offers. A filtering DNS blocks the resolution of malicious domains, newly registered domains and unwanted categories. It is a disproportionately effective control: it cuts phishing at the click and cuts command and control at the first call home, it works the same on a laptop at home and in the office, and there are free options or ones costing a few euros per user. For Nimbus it is, alongside MFA, the best purchase per euro in the catalogue. DNSSEC protects the integrity of the responses and is enabled on your own domain; DoH/DoT encrypt the query, with the trade-off that unmanaged DoH in the browser bypasses the corporate filtering, so it is configured explicitly.

Protecting your own domain. nimbusreservas.example is asset A-08, critical, and losing it means losing e-mail, the website and the ability to issue certificates. Four measures: a transfer lock at the registrar (registrar lock), MFA on the registrar account with two people having access, automatic renewal with an alert at 90 days — whole companies have gone down over an unrenewed domain — and a quarterly review of the zone, which is where forgotten records turn up.

Subdomain takeover. It is what the pentest found in 05-03. It happens when a CNAME or A record still points at a resource you no longer control — a deleted bucket, a decommissioned service, a released IP: anyone can claim that resource and serve content under your domain, with your valid certificate and, if the cookies are scoped broadly, with access to your users' sessions.

# Quarterly review: every record in the zone must respond and must be OURS
for sub in $(cat zone-nimbus.txt); do
  target=$(dig +short "$sub" CNAME)
  ip=$(dig +short "$sub" A | tail -1)
  # A CNAME pointing at a non-existent target (NXDOMAIN) is the classic sign of a
  # claimable subdomain: you delete the record, you do not "fix" the target.
  if [ -n "$target" ] && ! dig +short "$target" | grep -q .; then
      echo "RISK    $sub -> $target  (target does not exist: claimable)"
  fi
  echo "$sub  A=$ip"
done

  1. Protection against DoS and DDoS

It is worth being honest about what a company of 38 people can and cannot do.

Type What it does Can Nimbus handle it alone?
Volumetric (bandwidth flood) Saturates the link before it reaches your servers No. You need a provider with absorption capacity
Protocol (SYN flood and similar) Exhausts connection tables Partly: syncookies, stateful firewalls
Application (expensive requests) Brings the API down with a few well-chosen requests Yes, and this is the one that affects it most: rate limiting, caches, bounded queries, mandatory pagination

Realistic measures: a CDN or reverse proxy with anti-DDoS protection in front of the API and the website (there are free plans that are ample at this size), which also hides the origin's real IP — which must then accept traffic only from the CDN, or the attacker goes around it; rate limiting per IP, per customer and per tenant (02-04 and 05-05); autoscaling with a ceiling, because without a limit the attack stops being an outage and becomes an invoice; and mandatory pagination on the endpoints that return lists.

What to do during an attack, in order: confirm that it is an attack and not a legitimate spike or a fault of your own; enable the CDN's protection mode; do not disable logging (you lose the evidence exactly when it is needed); block by pattern at the edge and not at the origin; communicate honestly with customers (04-05); and do not pay any associated extortion. And afterwards: a post-mortem and threshold tuning.


  1. Network detection and the problem of encrypted traffic

Where the sensors are placed matters as much as which ones you choose:

Sensor Where What it contributes
Suricata (IDS/IPS) Inline at the office edge, or in listening mode on a mirror port Signature alerts; in IPS mode it blocks, with the risk of cutting legitimate traffic
Zeek In listening mode, office and VPC Rich logs: conn.log, dns.log, ssl.log, files transferred. It is the best raw material for 05-02
Flow logs (NetFlow / VPC Flow Logs) At the cloud provider Who talked to whom, how much and when. Cheap, with nothing decrypted and enough to see 1.2 TB going out
Firewall logs Everywhere What was blocked, which is where command and control shows up

What is lost with encryption. Today more than 90 % of traffic is encrypted, so a signature IDS sees far less than it did ten years ago. What is still visible without decrypting anything is a lot: who talks to whom, how much, in which direction and at what rhythm; the server name in the TLS handshake and the DNS queries; the certificate and the TLS client fingerprint. That is enough to detect exfiltration, periodic command and control and anomalous destinations. That is why flow and DNS logs deliver more, and come far cheaper, than trying to look inside.

The alternative — TLS inspection, that is, terminating the encryption on an intermediate device in order to read the content — has a cost that goes beyond the technical: it requires installing your own certificate authority on every machine, it exposes at that point everything people do, including their banking and their health, and it creates an extremely high-value target. For Nimbus the conclusion is clear: no TLS inspection is performed on employees' machines; the investment goes into flow, DNS and endpoint telemetry, which give almost the same signal without that cost. (Legal and employment validation note: in Spain, any measure that allows access to the content of staff communications requires prior notice, proportionality and, depending on the case, negotiation with the workers' representatives; it requires legal validation before being implemented. This is developed in 06-03 and 06-06.)


  1. Zero Trust applied to the network

Traditional perimeter Zero Trust
Assumption Inside is trusted, outside is not The network is never trusted
Access control By location (IP, VLAN) By identity + device + context, on every request
If a laptop is compromised Free lateral movement The laptop grants access to nothing on its own
Remote working An exception solved with a VPN The normal case: there is no inside or outside
flowchart LR
    U["User\nidentity verified\nwith MFA/FIDO2"] --> PD["DECISION POINT\nwho, which device,\nwhat context, what resource"]
    D["Device\nmanaged, encrypted,\nup to date (05-06)"] --> PD
    C["Context\ntime, country, risk,\nsensitivity of the resource"] --> PD
    PD -->|"allowed, bounded\nand time-limited"| R["A specific resource\n(one system, not the network)"]
    PD -->|"denied or\nextra second factor"| X["Log and alert\n(05-02)"]
    R --> V["Continuous verification:\nthe session is re-evaluated,\nnot granted forever"]

Zero Trust is not bought: it is implemented in phases, and for Nimbus the first three are already under way or free:

Phase What is done Cost Status
1 Strong identity: MFA/FIDO2 on every account, named accounts, an end to shared ones Low Under way (C-01)
2 Network segmentation and cloud microsegmentation (§2) None This lesson
3 Just-in-time access for third parties and for administration (§4) None Pending (C-03)
4 Device posture as a condition of access (encrypted, up to date, with an agent) Medium 05-06
5 Per-request authorisation in the application itself Medium 05-05
6 Continuous session re-evaluation and integrated telemetry High A 2-3 year goal

The practical warning: a VPN is not Zero Trust. A VPN that grants access to the whole internal network reproduces the perimeter under another name; it becomes a step towards Zero Trust only when what sits behind it is segmented and each service authenticates on its own.


  1. Verifying that the segmentation works

This is the section people skip most often and the one that decides whether everything above is real. An untested network design is a drawing, and the way to test it is to try, from each zone, to reach what should not be reachable.

#!/usr/bin/env bash
# verify-segmentation.sh - run FROM each zone, after every network change.
# Each line declares: destination, port, and whether the expectation is OPEN or CLOSED.
TESTS=(
  "10.30.20.5   5432 CLOSED   # DB from the users VLAN: R-03"
  "10.30.10.11    22 CLOSED   # direct SSH to the API without going through the bastion"
  "10.30.1.10     22 CLOSED   # the bastion host is NOT reachable without the VPN"
  "10.20.40.1    443 CLOSED   # management panel from the users network"
  "10.20.20.10   445 CLOSED   # NAS from the guest network"
  "10.30.90.7   6379 CLOSED   # preproduction Redis"
  "1.1.1.1        53 OPEN     # egress to the Internet: positive control"
)

failures=0
for test in "${TESTS[@]}"; do
  read -r host port expected _ <<< "$test"
  # -z: send no data. -w 3: 3 s timeout, so that a filtered port (which does not
  # respond) does not block the script indefinitely.
  if nc -z -w 3 "$host" "$port" 2>/dev/null; then actual="OPEN"; else actual="CLOSED"; fi

  if [ "$actual" = "$expected" ]; then
      printf 'OK    %-14s %-5s expected=%s\n' "$host" "$port" "$expected"
  else
      printf 'FAIL  %-14s %-5s expected=%s actual=%s\n' "$host" "$port" "$expected" "$actual"
      failures=$((failures+1))
  fi
done
echo "---"; echo "Failed tests: $failures"; exit $((failures > 0))

Four details make this script useful. It declares the expectation, so it doubles as executable documentation of the design. It includes a positive control (1.1.1.1:53 must be open): if everything comes back "closed", the most likely explanation is that the problem is the script itself or that there is no network, not that the segmentation is perfect. It returns a non-zero exit code, which lets you run it from the infrastructure CI after every change. And it is run from each zone, because the answer depends on the source: that means launching it from a laptop on the users VLAN, from the guest wifi, from the bastion host and from preproduction.

For a broader check, nmap from each zone against the others documents the real map:

# From a laptop on the guest VLAN: NOTHING internal should be visible
nmap -sn 10.20.10.0/24 10.20.20.0/24 10.20.40.0/24
# Expected output: "0 hosts up"

The mistake to avoid, and it is the most common one in the lesson: taking the segmentation on trust because the diagram is correct and the rules "are in place". Rules overlap, security groups are inherited, somebody opens something "just for a moment" to debug and does not close it, and a route table turns two separate zones into one. The only proof that two zones are separate is trying to cross between them and failing.


Common Mistakes and Tips

  • A flat network "because we're small". Size does not protect you (02-06): with 38 people and 40 laptops, a single compromised machine reaches everything.
  • Guests on a different SSID but without a separate VLAN. It is the same network with two names.
  • Trusting MAC filtering or hiding the SSID. They are not controls; they are administrative work with a feeling of security.
  • Opening SSH to the Internet and "compensating" with fail2ban. The right control is for it not to be reachable; fail2ban is the second line, not the first.
  • Not filtering egress. It is what enables exfiltration and command and control. Start in logging mode and enforce in two weeks.
  • A VPN that grants access to the whole internal network. It is the perimeter under another name; behind it there must be segmentation and per-service authentication.
  • Leaving DNS records for decommissioned resources. It is the door to subdomain takeover, with your domain and your certificate.
  • Tip: start with the three twenty-minute closures. 5432 restricted to the application subnet, 22 only from the bastion host and the VPN, and the A-19 exception revoked. It is the biggest drop in risk per hour invested in the whole course.
  • Tip: put the verification script into the infrastructure CI. If a rule is opened by mistake, you will know the same day and not at the next pentest.
  • Tip: filtering DNS is the best purchase per euro after MFA. It cuts phishing and command and control, it works inside and outside the office and it costs a few euros per user.

Exercises

Exercise 1 — Close the three historical holes

For each of the three findings outstanding since 05-01 — PostgreSQL on 0.0.0.0:5432, SSH open to 0.0.0.0/0 and the consultancy's permanent access (A-19) — write out: the specific change, the risk in the 04-01 register it reduces, the estimated time and how you would verify it is done.

Exercise 2 — Design the target office network

A former intern left this office configuration documented:

Single VLAN 10.20.0.0/16 for everything (laptops, NAS, printer, APs, meeting-room TV).
Corporate and guest wifi: same AP, separate SSIDs, no VLAN.
MAC filtering enabled on the AP. Guest SSID hidden.
Router: administration panel reachable from any machine on the network.
Router rule: allow everything outbound.
  1. Rewrite the design in zones with their ranges and their matrix of permitted communication.
  2. State which two "controls" have to be removed and why.
  3. Propose three egress rules and explain which attack each one cuts.

Exercise 3 — Interpret a failed verification

After applying the segmentation, Lucía runs the script from §10 from a laptop on the users VLAN and gets:

OK    10.30.20.5     5432 expected=CLOSED
FAIL  10.30.10.11    22   expected=CLOSED actual=OPEN
OK    10.30.1.10     22   expected=CLOSED
FAIL  10.20.40.1     443  expected=CLOSED actual=OPEN
OK    10.20.20.10    445  expected=CLOSED
FAIL  1.1.1.1        53   expected=OPEN actual=CLOSED

Interpret each failure, state the most likely cause and the order in which you would tackle them.


Solutions

Exercise 1

Hole Specific change Risk Time Verification
PostgreSQL on 0.0.0.0:5432 Ingress rule on the sg-data group referencing sg-app instead of 0.0.0.0/0; plus a bounded listen_addresses and pg_hba.conf restricted to the application subnet R-03 (25 → low residual) 20 min nmap -Pn -p 5432 from the Internet must return filtered; the script from §10 from the users VLAN must return CLOSED; and an API smoke test must still work
SSH open to 0.0.0.0/0 Port 22 removed from every group except sg-bastion; the bastion host only accepts 22 from the VPN subnet; ProxyJump in everybody's configuration R-07 and 82 % of the alert noise from 05-02 45 min External nmap: filtered on every host, including the bastion; a test connection with the VPN active and without it
A-19's permanent access Named accounts with MFA, request with a ticket, automatic 8 h expiry, access to the specific system and not to the network, alert D-03, and revocation of the 2023 exception in the register from 04-02 R-01, the highest-scoring risk in the register 1 day of work + the consultancy's signature Check that the shared account no longer authenticates; request a test access and verify that it expires on its own after 8 h; check that D-03 fires on an out-of-window access

The underlying observation: the most important of the three is not technical. The first two are firewall rules; the third requires a contractual conversation with a supplier, and that is why it has been outstanding for two years. That is the difference between 04-04 and this lesson.

Exercise 2

(1) Zones and matrix. The design is the one in the table in §2: VLAN 10 users (10.20.10.0/24), 20 local servers (10.20.20.0/24), 30 guests (10.20.30.0/24), 40 management (10.20.40.0/24) and 50 untrusted (10.20.50.0/24), with the meeting-room TV in 50 and the access points, the switch and the router in 40.

From ↓ / To → Users Servers Guests Management Untrusted Internet
Users Machine isolation Specific ports (printing, files) No No (except Lucía's laptop over the VPN) No Yes
Servers Responses only No No No Updates only
Guests No No Client isolation No No Yes
Management No No No No Updates only
Untrusted No No No No Yes, bounded

A detail that is usually forgotten: isolation within the users VLAN too. One laptop does not need to talk to another laptop, and that traffic is exactly what lateral movement and ransomware spreading across the local network use.

(2) The two "controls" to remove are MAC filtering and the hidden SSID. The first is bypassed by cloning a MAC address visible over the air, and in exchange it generates work every time a device joins. The second hides nothing — the network appears as soon as a client connects — and makes security worse: it forces laptops to go around asking for that SSID wherever they are, which makes it easy for a rogue access point to answer "yes, that's me". They are replaced by WPA3 or WPA2-Enterprise with an individual credential.

(3) Three egress rules:

  • Block everything outbound except 80/443, DNS to the internal resolver and NTP. It cuts command and control over non-standard ports and much generic malware, which usually calls home on high ports.
  • Block outbound DNS (53, known DoH) to any destination other than the corporate resolver. It cuts DNS exfiltration — a classic technique precisely because DNS is almost never filtered — and forces all traffic through the domain filter.
  • Block outbound SMB, RDP and SSH from the users VLAN to the Internet. There is no legitimate use case, and it cuts both exfiltration to external servers and reverse connections from a compromised machine.

Exercise 3

The third failure is the most important and has to be read first. 1.1.1.1:53 expected OPEN and actually CLOSED is the positive control, and its failure invalidates the other results: the laptop may have no network, outbound DNS may be blocked by the new egress rule (which would be correct and merely means changing the positive control to the internal resolver) or the script may be wrong. Without a valid positive control, the "OK"s on lines 1, 3 and 5 prove nothing: they could be closed for lack of connectivity and not because of segmentation.

Interpretation of the other two:

  • 10.30.10.11:22 open from the users VLAN. The bastion host is properly closed (line 3 is OK), but the API server still accepts SSH from outside the bastion. Most likely cause: the rule was applied to the new security group, but the instance retains a second membership in an older, more permissive group, and in the cloud groups add up, they do not subtract. It is the classic mistake. You review the instance's full list of groups, not just the one you have just edited.
  • 10.20.40.1:443 open: the router's management panel is reachable from the users network. Most likely cause: the management device listens on all its interfaces and not only on VLAN 40, or the inter-VLAN rule is missing. It is bound to the management interface and checked again.

Order of work: (1) fix the positive control and repeat the full test, because until then there are no reliable results; (2) the API's SSH, because it is administrative access from a user zone and amounts to having closed nothing; (3) the router panel, which is serious — it controls the network — but is a step below. And a cross-cutting conclusion: this script must run in the infrastructure CI after every change, because both failures are exactly the kind of residue nobody detects until the next pentest.


Conclusion

You have turned Nimbus's network from a drawing with seven problems into a defensible design, and you have done it without buying anything: all seven were configuration. You know why segmentation is the control with the best cost/impact ratio — it does not prevent the intrusion, it prevents it from becoming a catastrophe — you can distinguish VLAN, subnet, security group and microsegmentation, and you have the target zone design for the office (users, servers, guests, management, untrusted) and for the cloud (public with a bastion host, application, data, isolated preproduction), with the specific fix of 5432 restricted to the application subnet and 22 reachable only from the bastion host.

You know the types of firewall and where each one goes, the default policy of deny, and the control almost nobody applies: filtering egress, with commented nftables rules and their security-group equivalent that references groups and not IP ranges. You know that egress filtering costs one first week of undocumented dependencies and that this is precisely why it is worth doing, and that it is deployed in logging mode before being enforced. You set up remote access with WireGuard — one fixed IP per person so the logs identify somebody — and with an SSH bastion host using ProxyJump, where the private key never touches the jump host; and you know why a VPN is not Zero Trust if there is no segmentation behind it. You have closed A-19 with named accounts, MFA, a ticket, an 8-hour expiry, alert D-03 and the revocation of the 2023 exception.

You can choose between WPA2-Personal, WPA2-Enterprise and WPA3, isolate the guest network properly and explain why MAC filtering and a hidden SSID are not controls — the second one even makes security worse. You have a command of DNS on its three fronts: resolution and filtering as the best purchase per euro after MFA, DNSSEC, protection of domain A-08 with a transfer lock, MFA at the registrar and automatic renewal, and subdomain takeover with its quarterly check. You know what Nimbus can and cannot do against DDoS — the application kind yes, the volumetric kind no — and what to do during an attack. You know where to place Suricata, Zeek and the flow logs, what remains visible even when everything is encrypted (who talks to whom, how much, DNS and SNI) and why Nimbus will not perform TLS inspection on its staff's machines. And you have Zero Trust as a phased plan, with the first three phases free or under way.

Above all, you take away the discipline that separates the design from reality: the segmentation verification script, with declared expectations, a positive control, an exit code for CI and execution from each zone. The only proof that two zones are separate is trying to cross between them and failing.

The network no longer gives access away. But notice where the attack surface now sits: port 443 on the API is still open to the whole Internet, and it has to be, because that is where the product lives. No firewall rule distinguishes a legitimate booking from an attempt to read another clinic's data: only the application can make that distinction. In Application Security (05-05) we go into the code: a secure development lifecycle, concrete defences against the OWASP Top 10 with the fixes written out, centralised authorisation that generalises the IDOR lesson, API security, secrets management, headers and CSP, and a CI pipeline with SAST, DAST, SCA and secret scanning that decides what breaks the build and what merely warns.

Fundamentals of Information Security Course

Module 1: Introduction to Information Security

Module 2: Cybersecurity

Module 3: Cryptography

Module 4: Risk Management and Protection Measures

Module 5: Security Tools and Techniques

Module 6: Best Practices and Regulations

Module 7: Final Project

© Copyright 2026. All rights reserved