Objective

Conduct a structured threat assessment on a provided network topology representing a small business with a DMZ, internal LAN, and cloud-hosted application tier. Using the STRIDE threat model, identify attack vectors, rate risks using a likelihood-impact matrix, and implement compensating controls including Linux firewall rules (iptables/UFW), Azure Network Security Group rules, fail2ban configuration, and a hardened SSH policy. Document all findings in a structured security report.

Tools & Technologies

  • STRIDE threat modeling — Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege
  • iptables / UFW — Linux host-based firewall
  • Azure NSG — cloud-layer network security groups
  • fail2ban — automated brute-force protection
  • Nmap — port scanning and service enumeration
  • Lynis — Linux security audit tool
  • OpenVAS / Greenbone — vulnerability scanning
  • auditd — Linux kernel audit framework
  • CIS Benchmarks — security hardening reference

Architecture Overview

flowchart TD Internet[Internet\nUntrusted Zone] -->|TCP 80/443| DMZ Internet -->|SSH brute force| SSH_Risk[SSH Exposure Risk] DMZ[DMZ\nWeb Server\n172.16.1.10] -->|filtered| LAN LAN[Internal LAN\n192.168.1.0/24] --> DB[Database Server\n192.168.1.50] LAN --> FW[Linux Firewall\niptables + fail2ban] FW --> Internet SSH_Risk --> FW DB --> AUDIT[auditd\nDB Access Logging] style Internet fill:#181818,stroke:#1e1e1e,color:#888 style DMZ fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style LAN fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style DB fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style FW fill:#1a1a2e,stroke:#00ff88,color:#e0e0e0 style SSH_Risk fill:#181818,stroke:#1e1e1e,color:#888 style AUDIT fill:#1a1a2e,stroke:#00ff88,color:#e0e0e0

Step-by-Step Process

01
STRIDE Threat Identification

Applied STRIDE to each system component, documenting threat descriptions, affected assets, and initial risk ratings before any controls were in place.

# Threat register excerpt (documented in spreadsheet)
# Asset: Web Server (DMZ)
# S — Spoofing:    Attacker impersonates legitimate user via session hijacking
# T — Tampering:  Defacement via web application vulnerability (SQLi/RCE)
# R — Repudiation: No access logging configured on web server
# I — Info Disc:  Directory listing enabled, exposes file structure
# D — DoS:        No rate limiting; susceptible to HTTP flood
# E — EoP:        Running Apache as root increases blast radius

# Asset: SSH Service (Firewall/Servers)
# S — Spoofing:   Password authentication enables credential stuffing
# D — DoS:        Unlimited login attempts exhaust connection table
02
Reconnaissance & Vulnerability Scan

Used Nmap to enumerate open ports and services on the target topology, and Lynis to audit the Linux configuration against CIS benchmarks.

# Full port scan of web server
nmap -sV -sC -p- --min-rate 1000 172.16.1.10 -oN scan_webserver.txt

# OS detection and script scan
nmap -A -T4 192.168.1.50

# Linux security audit with Lynis
sudo lynis audit system --quick
# Review: /var/log/lynis.log
# Key findings: world-writable files, no password aging, no auditd

# Check for listening services
ss -tlnp
# Identify: Apache, sshd, mysqld, rpcbind (unexpected)
03
Firewall Hardening with iptables

Replaced the permissive default policy with a deny-all baseline, adding explicit rules for each required service. Applied connection tracking to statefully permit established sessions.

# Flush existing rules and set deny-all defaults
sudo iptables -F
sudo iptables -X
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow established/related connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow SSH only from management subnet
sudo iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT

# Allow HTTP/HTTPS to DMZ web server
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Log dropped packets
sudo iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4

# Persist
sudo iptables-save | sudo tee /etc/iptables/rules.v4
04
fail2ban Brute-Force Protection

Configured fail2ban with custom jails for SSH, Apache, and a custom application log pattern. Set ban thresholds appropriate for the environment.

# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 3600
findtime = 600
maxretry = 5
banaction = iptables-multiport

[sshd]
enabled  = true
port     = 22
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 86400

[apache-auth]
enabled  = true
port     = http,https
filter   = apache-auth
logpath  = /var/log/apache2/error.log
maxretry = 5

sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
05
auditd & SSH Hardening

Enabled the Linux audit daemon with rules to log privilege escalation, file access in sensitive directories, and all authentication events. Hardened SSH to use only ed25519 keys and modern ciphers.

# auditd rules — /etc/audit/rules.d/hardening.rules
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-a always,exit -F arch=b64 -S execve -F euid=0 -k root_commands
-w /var/log/auth.log -p rwa -k auth_log

sudo auditctl -R /etc/audit/rules.d/hardening.rules
sudo systemctl restart auditd
sudo ausearch -k identity | tail -20

# SSH hardening — /etc/ssh/sshd_config
Protocol 2
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KexAlgorithms curve25519-sha256,[email protected]
Ciphers [email protected],[email protected]
MACs [email protected]
LoginGraceTime 30
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

sudo sshd -t  # validate config
sudo systemctl restart ssh

Complete Workflow

flowchart LR A[STRIDE Threat\nModeling] --> B[Nmap + Lynis\nReconnaissance] B --> C[Risk Rating\nLikelihood × Impact] C --> D[iptables\nDeny-All + Explicit Rules] D --> E[fail2ban\nBrute-Force Protection] E --> F[auditd Rules\nAudit Logging] F --> G[SSH Hardening\nKey-Only + Modern Ciphers] G --> H[Re-scan to Verify\nControl Effectiveness] style A fill:#1a1a2e,stroke:#00d4ff,color:#e0e0e0 style H fill:#1a1a2e,stroke:#00ff88,color:#e0e0e0 style B fill:#181818,stroke:#1e1e1e,color:#888 style C fill:#181818,stroke:#1e1e1e,color:#888 style D fill:#181818,stroke:#1e1e1e,color:#888 style E fill:#181818,stroke:#1e1e1e,color:#888 style F fill:#181818,stroke:#1e1e1e,color:#888 style G fill:#181818,stroke:#1e1e1e,color:#888

Challenges & Solutions

  • iptables rules not surviving reboots — Rules are in-memory only by default. Installed iptables-persistent and used netfilter-persistent save to persist rules to /etc/iptables/rules.v4.
  • fail2ban banning legitimate admin IP — Initial config had no ignoreip setting. Added the management subnet to the [DEFAULT] ignore list in jail.local to prevent lockout.
  • auditd generating excessive log volume — The -a always,exit -S execve rule captured every single process execution. Narrowed to -F euid=0 to audit only root-level command execution.
  • Post-hardening SSH connection refused — The new cipher list excluded the algorithm the management workstation's older OpenSSH client was using. Added one compatible modern cipher to allow the admin workstation to connect.

Key Takeaways

  • STRIDE is most effective when applied per-component, not per-system — each asset has a different threat profile that requires targeted controls.
  • Deny-all firewall policies with explicit allow rules are significantly more secure than permit-all with explicit deny — the attack surface is minimized by default.
  • fail2ban requires an ignoreip configuration for all management networks — getting locked out of a production server by your own security tool is a real operational risk.
  • auditd rules need careful tuning between coverage and log volume — over-auditing creates noise that obscures genuine security events during analysis.