diff --git a/README.md b/README.md index 5482817..7ac72ac 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ +![Workflow Timeline](workflow_status.svg) # BrokenOps diff --git a/labs/nginx-broken/cloud-init.yaml b/labs/nginx-broken/cloud-init.yaml index b4bad6f..274045b 100644 --- a/labs/nginx-broken/cloud-init.yaml +++ b/labs/nginx-broken/cloud-init.yaml @@ -1,8 +1,16 @@ #cloud-config packages: - nginx + - policycoreutils + - selinux-utils + - policycoreutils-python-utils + - auditd runcmd: - # Intentional break: configure nginx to listen on invalid port to break it - - sed -i 's/listen 80 default_server;/listen 80808 default_server;/' /etc/nginx/sites-available/default + # Intentional break: move nginx to 8080, but do not allow SELinux http_port_t on 8080. + - sed -i 's/listen 80 default_server;/listen 8080 default_server;/' /etc/nginx/sites-available/default + - sed -i 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' /etc/nginx/sites-available/default + - systemctl enable --now auditd || true + - setenforce 1 || true + - semanage port -d -t http_port_t -p tcp 8080 || true - systemctl restart nginx || true diff --git a/labs/nginx-broken/lab.yaml b/labs/nginx-broken/lab.yaml index 7867bec..cbc052f 100644 --- a/labs/nginx-broken/lab.yaml +++ b/labs/nginx-broken/lab.yaml @@ -1,6 +1,6 @@ id: nginx-broken -name: Nginx Service Down +name: SELinux Denies Nginx on Custom Port category: linux difficulty: beginner @@ -17,18 +17,18 @@ vm: cloud_init: cloud-init.yaml verify_script: verify.sh exposed_ports: - - 80 + - 8080 verify: verify.sh description: - summary: "Nginx is not running after reboot" - story: "A server reboot caused nginx to stop." + summary: "Nginx runs but app is unreachable on port 8080" + story: "Nginx was moved to port 8080, but SELinux policy was never updated." objectives: - - Start nginx - - Enable service on boot - - Confirm HTTP response + - Investigate SELinux denials for nginx + - Map TCP port 8080 to http_port_t + - Confirm HTTP response on port 8080 tags: - - systemd + - selinux - nginx diff --git a/labs/nginx-broken/question.md b/labs/nginx-broken/question.md index c290fa6..45a2526 100644 --- a/labs/nginx-broken/question.md +++ b/labs/nginx-broken/question.md @@ -1,13 +1,19 @@ ### Scenario -You have just joined a new company as a junior sysadmin. A developer frantically messages you: -> "Hey! The main Nginx web server is completely down on our internal staging box. The service won't start at all after I accidentally rebooted it! I need to test my new frontend right now, can you please fix it?" +Nginx was reconfigured to use port **8080** on a host where SELinux is expected to remain enforcing. +The service appears configured, but the app is unreachable. ### Objective -Investigate why the `nginx` service is failing to start on this machine, fix the root cause, and ensure the service is running. -Once running, the web server should be accessible via the **"Open Port 80"** button in the top navigation bar. When clicked, it should display the default Nginx welcome page. +Find and fix the SELinux policy issue preventing HTTP service on the custom port while keeping SELinux enforcing. + +When solved: +- Nginx should run on **port 8080** +- SELinux should allow HTTP traffic on 8080 (`http_port_t` mapping) +- The **"Open Port 8080"** button should load the Nginx default page ### Useful Commands - `systemctl status nginx` - `journalctl -xeu nginx.service` +- `ausearch -m avc -ts recent` +- `semanage port -l | grep http_port_t` diff --git a/labs/nginx-broken/solution.md b/labs/nginx-broken/solution.md index 8d3590c..4931174 100644 --- a/labs/nginx-broken/solution.md +++ b/labs/nginx-broken/solution.md @@ -1,42 +1,40 @@ ### The Issue -The developer or someone else accidentally configured Nginx to listen on a port that it doesn't have permission to bind to, or they made a syntax error in the configuration file! +Nginx was moved to TCP port `8080`, but SELinux policy did not allow HTTP services on that port. +So nginx fails to bind when SELinux is enforcing. ### Step-by-Step Fix -1. **Check the service status to get a hint:** +1. **Check nginx status and logs:** ```bash systemctl status nginx + journalctl -xeu nginx.service ``` - You should see it failing. -2. **Test the Nginx configuration for syntax errors:** +2. **Check SELinux denials:** ```bash - sudo nginx -t + ausearch -m avc -ts recent ``` - This will pinpoint exactly which file and line number contains the bad configuration. You'll likely see an error pointing to `/etc/nginx/sites-available/default` trying to listen on port `80808` or a typo like `lissten 80`. -3. **Fix the configuration file:** - Open the file with your favorite editor: +3. **Confirm the custom port is not mapped to `http_port_t`:** ```bash - sudo nano /etc/nginx/sites-available/default - ``` - Find the incorrect line and fix it back to listening on a standard port like `80`: - ```nginx - server { - listen 80 default_server; - listen [::]:80 default_server; - # ... - } + semanage port -l | grep http_port_t ``` -4. **Restart the Nginx service:** +4. **Map TCP 8080 for HTTP services:** ```bash - sudo systemctl restart nginx + sudo semanage port -a -t http_port_t -p tcp 8080 + ``` + If it already exists with a different type, modify it instead: + ```bash + sudo semanage port -m -t http_port_t -p tcp 8080 ``` -5. **Verify it's running:** +5. **Restart nginx and verify:** ```bash - systemctl status nginx + sudo systemctl restart nginx + ss -tuln | grep ':8080 ' + curl -I http://127.0.0.1:8080 ``` - It should now say **active (running)**. You've solved the lab! + +You have solved the lab once nginx is reachable on port `8080` with SELinux still enforcing. diff --git a/labs/nginx-broken/solution.sh b/labs/nginx-broken/solution.sh new file mode 100755 index 0000000..f7ee0bf --- /dev/null +++ b/labs/nginx-broken/solution.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +# Keep nginx on custom port 8080 +sed -i 's/listen 80 default_server;/listen 8080 default_server;/' /etc/nginx/sites-available/default || true +sed -i 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' /etc/nginx/sites-available/default || true + +# Ensure SELinux allows HTTP traffic on tcp/8080 +if ! semanage port -l | awk '/^http_port_t/ && /(^|[^0-9])8080([^0-9]|$)/ {found=1} END {exit found?0:1}'; then + semanage port -a -t http_port_t -p tcp 8080 || semanage port -m -t http_port_t -p tcp 8080 +fi + +systemctl restart nginx diff --git a/labs/nginx-broken/verify.sh b/labs/nginx-broken/verify.sh old mode 100644 new mode 100755 index acf7136..0a9a379 --- a/labs/nginx-broken/verify.sh +++ b/labs/nginx-broken/verify.sh @@ -3,16 +3,30 @@ # Check if nginx service is active systemctl is-active --quiet nginx if [ $? -ne 0 ]; then - echo "FAILURE: The nginx service is not running." + echo "FAILURE: nginx service is not running." exit 1 fi -# Check if it's actually listening on port 80 -ss -tuln | grep ":80 " > /dev/null +# Check if nginx is listening on port 8080 +ss -tuln | grep ':8080 ' > /dev/null if [ $? -ne 0 ]; then - echo "FAILURE: Nginx is running, but it's not listening on port 80!" + echo "FAILURE: nginx is not listening on port 8080." exit 1 fi -echo "SUCCESS: Nginx is running and listening on port 80!" +# Check SELinux port context mapping for HTTP on 8080 +semanage port -l | awk '/^http_port_t/ && /(^|[^0-9])8080([^0-9]|$)/ {found=1} END {exit found?0:1}' +if [ $? -ne 0 ]; then + echo "FAILURE: SELinux is not allowing HTTP service on tcp/8080 (http_port_t mapping missing)." + exit 1 +fi + +# Check HTTP response over localhost +curl -sSf http://127.0.0.1:8080 > /dev/null +if [ $? -ne 0 ]; then + echo "FAILURE: nginx is running on 8080 but HTTP request failed." + exit 1 +fi + +echo "SUCCESS: nginx is serving on 8080 and SELinux http_port_t mapping is set for tcp/8080." exit 0 diff --git a/workflow_status.svg b/workflow_status.svg index 5f2e518..82843e6 100644 --- a/workflow_status.svg +++ b/workflow_status.svg @@ -11,31 +11,47 @@ Workflow Execution Report -Commit: a0dc113 • Triggered: 2026-06-05 13:28:35 +Commit: 11f2d59 • Triggered: 2026-06-05 14:23:50 - -Remove Solutions on Main -2026-06-05 13:28:19 • trigger: push + +CI Verify Labs +2026-06-05 14:23:38 • trigger: pull_request - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + -SUCCESS (6s) +FAILURE (154s) -CI Verify Labs -2026-06-05 12:25:41 • prev trigger: pull_request +Remove Solutions on Main +2026-06-05 13:28:19 • prev trigger: push -SUCCESS (Last: 122s) +SUCCESS (Last: 6s) Generate and Embed Banner