Skip to content
DevOps AI ToolKit
Newsletter

Kali Linux Networking for DevOps · Part 11 of 15

Nmap for DevOps Network Validation

Difficulty: Intermediate ~19 min Part 11/15
Prerequisites: Ports & listening servicesTCP vs UDP
Series progress11 / 15
Series curriculum (15 lessons)

Every deploy ships with an intention about network exposure: “this server should answer on SSH, HTTP, and HTTPS, and nothing else.” That intention lives in a firewall rule, a cloud security group, or a Kubernetes NetworkPolicy. But a config file describes what you asked for — it does not prove what a machine on the network actually sees. Nmap (“Network Mapper”) closes that gap. It is a measurement instrument: point it at infrastructure you own, read the ports it reports, and compare that observed reality against what you declared.

This lesson frames Nmap entirely as authorized infrastructure validation — a defensive practice, not an attack. We are not breaking into anything. We are asserting, after every deploy, that the exposure we observe matches the exposure we specified. An unexpected open port stops being a surprise incident and becomes a finding your validation caught before an attacker did.

🔐 Security Note — Only scan, inspect, or test systems you own or have explicit permission to assess. Do this work in a controlled lab — for example a host-only network on 192.168.56.0/24, or the isolated Kali Docker lab from this series. Scanning hosts you do not control can be illegal, will trip intrusion-detection systems, and can page an on-call engineer. Every example below targets a lab host you own.

What You Will Learn

  • Why Nmap belongs in a DevOps validation workflow, not just a pentest kit
  • Basic port discovery with nmap and what its default scan actually does
  • Scanning specific ports to assert an expected exposure
  • A repeatable methodology for comparing declared vs observed exposure
  • Confirming what is on a port with service/version detection (-sV)
  • How raw scan types (-sS) need extra privileges, and the safe container way to grant them

Nmap as a Validation Instrument

Recall the simplified troubleshooting stack we use throughout this series:

Application → TLS → Port → DNS → Gateway → Route → Interface

Most of this series diagnoses why a connection fails. Nmap works one layer at a time on the Port layer, but it answers the opposite question: which ports are reachable that I did not expect to be reachable? A failed connection is loud — something times out and someone files a ticket. An extra open port is silent. Nothing breaks. The service works fine. Meanwhile a management port or a database is quietly listening on an interface it never should have. Silent problems are the dangerous ones, and Nmap is how you make them loud on your own terms.

Before scanning anything, make sure you understand what a port is and how a process comes to be listening on one — that is the ports and listening services lesson — and the difference between the two transport protocols Nmap can probe, covered in TCP vs UDP.

Basic Port Discovery

Start with the simplest possible scan against a lab host. Assume 192.168.56.10 is a server on your host-only network.

nmap 192.168.56.10

Run with no flags, Nmap does a default TCP scan of the 1,000 most common ports. It does not scan all 65,535 ports, and it does not touch UDP. For each of those common ports it reports one of three states:

  • open — a service accepted the connection. Something is listening.
  • closed — the host replied but nothing is listening on that port.
  • filtered — no reply came back at all, which usually means a firewall or security group is dropping the packet rather than rejecting it.

Typical output looks like this:

PORT    STATE  SERVICE
22/tcp  open   ssh
80/tcp  open   http
443/tcp open   https

What does this output tell us? Three services are reachable on this host from wherever we ran the scan. The SERVICE column is Nmap’s guess based on the port number alone — port 80 is conventionally HTTP, so it prints http. That is a convention, not proof; we will confirm it properly further down. The important reading here is the STATE column: these three ports are open, and every other common port that Nmap probed came back closed or filtered and was summarized rather than listed.

🔐 Security Note — Keep pointing at your lab. If you substitute a real production host or a third-party IP here, you have crossed from validation into unauthorized scanning. Practice on 192.168.56.10, a VM you started, or the Kali Docker lab — never a machine you do not own.

🔎 Troubleshooting Tipclosed and filtered mean different things and the distinction is diagnostic. closed means the host is up and actively refused (the packet reached the TCP stack and got a reset — the Connection refused signature). filtered means the packet vanished (dropped by a firewall or security group — the Connection timeout signature). If a port you expected to be open shows filtered, suspect the firewall or a cloud security group before you suspect the service.

Scanning Specific Ports

A default scan is good for discovery, but validation is usually a targeted assertion: “these exact ports should be open.” Scan only the ports in your spec with -p:

nmap -p 22,80,443 192.168.56.10

The -p flag restricts the scan to the comma-separated list of ports — here 22 (SSH), 80 (HTTP), and 443 (HTTPS). This is faster than the 1,000-port default and, more importantly, it maps directly onto a declared configuration. You wrote a security group that allows exactly these three ports; now you scan for exactly these three ports and confirm each one reports open. You can also express ranges (-p 1-1024) or scan everything (-p-, all 65,535) when you are hunting for surprises rather than confirming a known list.

Targeted scans are what you wire into a post-deploy check. Discovery scans (nmap host or -p-) are what you run periodically to catch the exposure your spec forgot to mention.

A Real Validation: Declared vs Observed

Here is the everyday case. A new server is supposed to expose only SSH, HTTP, and HTTPS. That is the declared configuration — say, a security group that allows 22, 80, and 443. Your expected exposure is therefore:

22
80
443

Now you scan the running host and read the observed exposure:

22
80
443
3306

Compare the two lists. Port 3306 appears in the observed set but not the expected set. Port 3306 is MySQL. Nothing in your declared configuration said MySQL should be reachable — yet a database is answering on the network. This is a finding. Maybe the database container published its port to 0.0.0.0 instead of binding to localhost; maybe a security group rule is broader than intended; maybe someone added a rule for debugging and forgot to remove it. You do not yet know the cause, but you have caught the symptom, and you caught it before an attacker’s scanner did.

🏭 Why This Matters in Production — An exposed 3306 (MySQL), 5432 (Postgres), 6379 (Redis), or 27017 (MongoDB) is one of the most common real-world breach paths: an unauthenticated or weakly-authenticated datastore reachable from the internet. The config file said “internal only.” The observed scan said otherwise. The scan is the source of truth, because the scan is what an attacker also sees.

The DevOps Validation Methodology

The comparison above is not a one-off. It is a loop you run on every meaningful network change. Write it down and make it repeatable:

Declared Configuration

Expected Exposure

Observed Exposure   (nmap)

     Compare

     Correct

     Retest

Walk through it:

  • Declared Configuration — the security group, firewall ruleset, or NetworkPolicy as written in your IaC.
  • Expected Exposure — the plain list of ports that configuration should produce. Derive this deliberately; do not skip it, because half the value is forcing yourself to state the intent.
  • Observed Exposure — what nmap actually reports from the network.
  • Compare — diff the two lists. Extra ports are findings; missing ports are broken deploys.
  • Correct — fix the configuration (tighten the rule, rebind the service, remove the leftover debug port).
  • Retest — scan again. Validation is not done until the observed set equals the expected set.

🛠️ DevOps Perspective — This turns “the firewall/security group should only allow X” from a hopeful comment into a testable assertion you can run after every deploy. It is the same discipline as asserting an HTTP endpoint returns 200 in a smoke test — you are just asserting exposure instead of a status code. An unexpected open port is a failed assertion, and a failed assertion is a finding, not a shrug.

Confirming What Is Really on a Port

The default scan labels ports by convention: it sees 80 open and prints http. But conventions lie. Someone can run SSH on port 443 to slip past a naive firewall, or leave a forgotten admin panel on 8080. When a port matters, confirm what is actually answering with service and version detection:

nmap -sV -p 22,80,443 192.168.56.10

The -sV flag makes Nmap connect to each open port and read the service’s banner and response, then match it against a signature database to identify the software and often its version. Instead of a bare guess like 443/tcp open https, you get something concrete such as 443/tcp open ssl/http nginx 1.25.3. Now you know it is genuinely nginx speaking HTTPS, not something masquerading on that port. For validation this matters twice over: it confirms the right service is on the right port, and the version string can flag software you meant to patch. (Version banners are also useful evidence when you later cross-check against TLS certificate troubleshooting.)

A Note on Scan Types and Privileges

You may see guides reach for -sS, the SYN scan (“half-open” scan). It sends a raw SYN packet and never completes the TCP handshake, which is faster and stealthier. The catch: crafting raw packets requires elevated privileges. Run -sS as an unprivileged user and Nmap silently falls back to a normal connect scan, or errors out. The default connect scan (-sT, which uses the OS’s normal socket calls) needs no special privileges and is perfectly adequate for validation work — you rarely need -sS to answer “is this port open?”

If you are running Nmap inside a container (the Kali Docker lab), the right way to grant raw-socket ability is a narrow capability, not blanket privilege:

docker run --rm --cap-add NET_RAW kali-nmap \
  nmap -sS -p 22,80,443 192.168.56.10

--cap-add NET_RAW grants exactly the one Linux capability that raw packet crafting needs, and nothing else.

🔐 Security NoteNever use --privileged to make -sS work. --privileged hands the container nearly all host capabilities and effectively removes the isolation boundary — a wildly disproportionate grant for one scan flag. Prefer the least-privilege --cap-add NET_RAW (add --cap-add NET_ADMIN only if you also need to manipulate interfaces). This is the same container-security principle covered in the Docker series; keep the blast radius as small as the task requires.

Try It Yourself

🧪 Try It — Do a full declared-vs-observed loop in your lab, then break it on purpose so you can catch it.

  1. Stand up a lab host (a VM on 192.168.56.0/24 or a container in the Kali Docker lab) running nginx on 80 and 443 with SSH on 22.
  2. Write down your expected exposure: 22, 80, 443.
  3. Discover with nmap 192.168.56.10. Do the observed ports match your list?
  4. Assert precisely with nmap -p 22,80,443 192.168.56.10 — confirm all three read open.
  5. Confirm the software with nmap -sV -p 22,80,443 192.168.56.10. Is nginx really on 80 and 443?
  6. Now publish a database container’s port (start MySQL/Postgres bound to 0.0.0.0). Rescan with nmap 192.168.56.10. Watch 3306 (or 5432) appear — your injected finding.
  7. Correct it (bind the datastore to localhost or drop the security-group rule) and retest. Validation passes only when observed equals expected again.

Common Problems

  • Every port shows filtered — a firewall is dropping all your probes, or you are scanning across a network boundary that blocks the traffic. Confirm basic reachability first with the testing connectivity techniques before trusting a scan result.
  • A port you know is open shows closed — you are likely scanning the wrong interface or a NAT is in play. Verify the host is actually listening locally (from the host itself) before blaming the scan.
  • -sS seems to do nothing or errors — you lack raw-socket privilege. Use the default connect scan, or add --cap-add NET_RAW in a container. Never reach for --privileged.
  • Scans are painfully slow — the default 1,000-port scan across many hosts takes time, and UDP scanning is far slower still. Narrow with -p to the ports your spec actually cares about.
  • The scan pages your on-call — aggressive scans trip IDS. Announce scans of shared environments in advance and prefer an isolated lab for practice.

Troubleshooting Workflow

When a scan result surprises you, do not immediately “fix by restarting.” Diagnose the layer:

Observe    → nmap reports an unexpected open port
Hypothesis → the service published to 0.0.0.0
             OR a security-group rule is too broad
Test       → nmap -sV on that port; check the host's
             own listeners; read the IaC rule
Evidence   → -sV shows mysqld; host shows it bound
             to 0.0.0.0, not 127.0.0.1
Identify   → Port layer: exposure, not the app itself
Correct    → rebind to localhost or tighten the rule
Validate   → rescan; observed now equals expected

Identifying which layer is broken keeps you from thrashing. An extra open port is almost always an exposure problem (how the service is bound, or how the firewall is configured) — not a bug in the application on that port.

What You Learned

  • Nmap is a validation instrument, not just a pentest tool — you use it defensively to measure your own infrastructure’s exposure.
  • nmap 192.168.56.10 runs a default TCP scan of the 1,000 most common ports and reports each as open, closed, or filtered.
  • nmap -p 22,80,443 192.168.56.10 scans an exact port list, mapping directly onto a declared configuration you want to assert.
  • closed vs filtered is diagnostic: closed is Connection refused (host rejected), filtered is Connection timeout (packet dropped by a firewall).
  • The methodology: Declared Configuration → Expected Exposure → Observed Exposure → Compare → Correct → Retest. An unexpected open port (like a stray 3306) is a finding.
  • -sV confirms what is genuinely on a port instead of trusting the port-number convention.
  • Raw scan types (-sS) need extra privilege — grant it narrowly with --cap-add NET_RAW in a container; never --privileged.
  • Only ever scan systems you own or are authorized to assess, in a controlled lab.

You now have a repeatable way to assert exposure. For deeper context, compare this with the getting-started Nmap for DevOps lesson and the container-focused Nmap service discovery walkthrough.

Next up is Part 12: Packet Capture With tcpdump — where we drop below the port layer to watch the actual packets on the wire, so you can see not just that a port is open but exactly what is flowing through it.

Affiliate Disclosure: Some links on this page are affiliate links. If you purchase through one of these links, DevOps AI Toolkit may earn a commission at no additional cost to you. See our affiliate disclosure.

← Back to Kali Linux Networking for DevOps Back to Kali Linux

Related on DevOps AI Toolkit