Lab — Week 6: Policy, Access Control, and Host Firewall
Due: 14 August 2026
Submission: GitLab repo secdevops-s26-<CECS>
- Overview
- Prerequisites
- Part 1: Secrets Detection — Your Course Repo
- Part 2: Policy-as-Code with auditd and AppArmor
- Part 3: IAM, Host Firewall, and Automated Response
- Submission
Overview
Add the final layer of host-side controls: policy-as-code, least-privilege access, and a host firewall with automated response.
- Part 1 — Policy-as-Code with auditd and AppArmor implements auditd rules that log privileged operations, connects those events to Wazuh, and confines nginx with an AppArmor profile.
- Part 2 — IAM, Host Firewall, and Automated Response applies least privilege at three levels: service-account restrictions, an nftables host firewall, and fail2ban automated response.
Prerequisites
- Week 4 Part 2 complete — Wazuh agent active on ubuntu-server
- auditd, apparmor-utils, nftables, and fail2ban installed (by Ansible)
Part 1: Secrets Detection — Your Course Repo
- Run gitleaks across the full history of your course repo:
cd ~/path/to/secdevops-s26-<CECS> gitleaks git . \ --report-format json \ --report-path lab09/gitleaks-report.jsonℹ️
gitleaks gitscans commit history;gitleaks dirscans only the working tree. Older handouts and blog posts usegitleaks detect --source ., which was renamed in gitleaks 8.19 — the old form still runs but is hidden from--help.
Part 2: Policy-as-Code with auditd and AppArmor
Security controls written as code are enforced continuously, are version-controlled, and are testable. This part implements auditd rules that log privileged operations on ubuntu-server, connects those events to the Wazuh dashboard, and confines nginx with an AppArmor profile.
auditd Rules
-
Enable and start auditd:
sudo systemctl enable --now auditd - Write
/etc/audit/rules.d/dvwa.ruleswith the following rules. Each rule must include a-kkey tag:- Watch
/etc/shadowfor read access - Watch
/etc/sudoersand/etc/sudoers.d/for any write - Audit all executions by UID 0 (syscall
execve) - Watch
/var/ossec/etc/ossec.conffor any modification - Watch the Docker socket
/var/run/docker.sockfor access
- Watch
-
Load the rules:
sudo augenrules --load -
Verify the rules are active:
sudo auditctl -l - Trigger each rule deliberately and confirm events appear:
sudo cat /etc/shadow # triggers shadow_access key sudo touch /etc/sudoers.d/test && sudo rm /etc/sudoers.d/test # triggers sudoers key sudo ls / # triggers root_exec key - Search for triggered events:
sudo ausearch -k shadow_access --start today sudo ausearch -k root_exec --start today -
Confirm the same events appear in the Wazuh dashboard under Security Events, filtered by
rule.groups: audit. Take a screenshot. - Commit
etc/audit/rules.d/dvwa.rules(the file itself, not the system path) to your repo.
AppArmor Profile for nginx
- Generate an AppArmor profile for nginx using complain mode:
sudo aa-genprof nginxWhile
aa-genprofis running, send a few HTTP requests through nginx so the tool can observe normal behavior:curl http://localhost -
Review and refine the generated profile with:
sudo aa-logprof - Switch nginx to enforce mode:
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx -
Verify nginx still serves DVWA correctly:
curl -s -o /dev/null -w "%{http_code}" http://localhost -
Confirm the profile is in enforce mode:
sudo aa-status | grep nginx - Save the profile to your repo as
lab11/nginx-apparmor-profile.
Threat Model Update
- In
lab02/threat-model.md, mark threats mitigated by auditd and AppArmor. Add a note for each: what STRIDE category it addresses and the specific rule or profile that enforces it.
Deliverables
Create lab11/ in your repo containing:
dvwa.rules— your auditd rules fileausearchoutput — showing each rule triggering at least once- Wazuh screenshot — auditd events visible in Security Events dashboard
nginx-apparmor-profile— the AppArmor profile for nginx- nginx health check —
curloutput showing HTTP 200 after enforce mode is set aa-statusoutput — showing nginx profile in enforce mode- Updated
lab02/threat-model.md lab11/lab11.md— for each auditd rule, state which threat model entry it addresses and which STRIDE category it covers
Part 3: IAM, Host Firewall, and Automated Response
Least privilege applied at three levels in one part: service account restrictions limit what the DVWA process can do if compromised, nftables enforces which network paths are permitted, and fail2ban automatically blocks brute-force sources — all before a human can react.
Part 1 must be complete — auditd running on ubuntu-server.
Service Account Hardening
- Create a dedicated service account for DVWA with no login shell and no home directory:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin dvwa-svc - Create
/etc/sudoers.d/dvwathat grantsdvwa-svcthe single ability to restart its own container and nothing else:dvwa-svc ALL=(root) NOPASSWD: /usr/bin/systemctl restart dvwa -
Verify the restriction:
sudo -l -U dvwa-svcThe output must show exactly that one command and no others. - Attempt a restricted command and confirm it fails:
sudo -u dvwa-svc sudo bash # must be denied
nftables Host Firewall
- Write
/etc/nftables.d/lab.nftimplementing the following policy (commit it to your repo):- Allow established and related connections (return traffic)
- Allow SSH only from
10.10.10.10(Kali) - Allow HTTP (80) and HTTPS (443) from any source
- Allow MariaDB (3306) from
127.0.0.1only - Drop all other inbound traffic
- Allow all outbound traffic
- Apply the ruleset:
sudo nft -f /etc/nftables.d/lab.nft sudo nft list ruleset # verify - Test from Kali (10.10.10.10):
ssh dmcgrath@10.10.10.20 # must succeed curl http://10.10.10.20/ # must succeed - Verify MariaDB is unreachable from Kali:
nc -zv 10.10.10.20 3306 # must fail / time out
fail2ban Configuration
- Configure
/etc/fail2ban/jail.local:- SSH jail:
maxretry=3,findtime=600,bantime=3600, usingnftables-multiportbanaction - nginx jail: pattern-match the DVWA login endpoint (
/dvwa/login.php) for repeated HTTP 401 responses;maxretry=5,findtime=60,bantime=3600
- SSH jail:
-
Enable and start fail2ban:
sudo systemctl enable --now fail2ban - From Kali, trigger the SSH ban:
for i in {1..5}; do ssh wronguser@10.10.10.20; done - On ubuntu-server, confirm the ban:
sudo fail2ban-client status sshd # Shows: Banned IP list: 10.10.10.10
Confirming the Ban in Wazuh
Two separate things reach the SIEM when you trigger a ban, and you need both:
- The failed logins themselves, which sshd writes to
/var/log/auth.log. The Wazuh agent already monitors that file (default configuration from Week 4), so these alerts appear with no extra work. - The ban action, which fail2ban writes to its own log,
/var/log/fail2ban.log. Nothing monitors that file by default — the agent has no idea it exists. You must tell it to read the file, or the ban will never appear in the dashboard no matter how many times you trigger it.
- On ubuntu-server, confirm fail2ban actually logged the ban locally before looking at the dashboard:
sudo grep -E 'Ban|Found' /var/log/fail2ban.log | tail -10 # Expect a line like: fail2ban.actions [...] NOTICE [sshd] Ban 10.10.10.10If
/var/log/fail2ban.logdoes not exist, checklogtargetin/etc/fail2ban/fail2ban.conf— on some installs it is set toSYSLOGorSYSTEMD, in which case the ban lands in the journal instead and you should point the agent at/var/log/syslog. - Add the fail2ban log to the Wazuh agent’s monitored files. Edit
/var/ossec/etc/ossec.confon ubuntu-server and add the following inside<ossec_config>:<localfile> <log_format>syslog</log_format> <location>/var/log/fail2ban.log</location> </localfile>Restart the agent:
sudo systemctl restart wazuh-agent - Re-trigger the ban so events are generated after the agent started reading the file (unban first, since Kali is still blocked from step 12):
sudo fail2ban-client set sshd unbanip 10.10.10.10Then repeat the failed-login loop from Kali (step 11), and re-check
fail2ban-client status sshd. -
In the Wazuh dashboard (
https://10.10.10.30), go to Modules → Security Events, select agentubuntu-server, and set the time range to Last 15 minutes. In the search bar, apply each of these filters in turn:Filter What you should see rule.groups: authentication_failuresThe brute-force detection from auth.log— typically rule 5712, “sshd: brute force trying to get access to the system”rule.groups: fail2banThe ban action itself — a “Fail2ban: host banned” style alert sourced from /var/log/fail2ban.logdata.srcip: 10.10.10.10Everything the SIEM recorded about Kali during the attack, both of the above together If the
fail2bangroup filter returns nothing, drop back to a free-text search for10.10.10.10over the same window and look for the alert whosefull_logfield contains theBan 10.10.10.10line — that confirms the log is being ingested even if it matched a different rule group. -
Expand one ban alert in the dashboard and record its rule ID, rule level, and description; you will cite these in
lab12.md. Take a screenshot showing the expanded alert with the source IP and rule description visible. - Unban Kali before finishing:
sudo fail2ban-client set sshd unbanip 10.10.10.10
Threat Model — Final Update for Preventive Controls
- In
lab02/threat-model.md, mark all threats now addressed by service account restrictions, nftables rules, or fail2ban. This should bring nearly all of your top 5 threats to MITIGATED status.
Deliverables
Create lab12/ in your repo containing:
/etc/sudoers.d/dvwa— the sudoers filesudo -l -U dvwa-svcoutput — showing only the permitted commandlab.nft— the nftables rulesetnft list rulesetoutput — confirming rules are loaded- Network test results — SSH and HTTP success from Kali; MariaDB failure from Kali
/etc/fail2ban/jail.local— fail2ban configuration- fail2ban ban confirmation —
fail2ban-client status sshdshowing Kali IP banned - fail2ban log excerpt — the
Ban 10.10.10.10line from/var/log/fail2ban.log localfilestanza — the block you added to/var/ossec/etc/ossec.conffor/var/log/fail2ban.log- Wazuh alert screenshot — expanded fail2ban ban alert in Modules → Security Events, source IP and rule description visible
- Updated
lab02/threat-model.md— near-complete mitigation of top 5 threats lab12/lab12.md— brief explanation of how each control maps to your threat model; the rule ID, level, and description of the fail2ban ban alert you observed in Wazuh; and one threat that remains open with a reason why it cannot be fully mitigated by these controls
Submission
Commit all files for both parts — lab11/ and lab12/ — and push to your GitLab repo. The lab is considered submitted when the commit appears in GitLab before the due date.