Phase 0: Hands-On Job-Essential Lab Solutions
This module contains complete, step-by-step code solutions, terminal verification commands, and architectural explanations for the Phase 0 Job-Essential Exercises.
🛠️ Lab 1: The Automated Linux Web Server Bootstrap Script
Objective
Write an automated, idempotent Bash script (setup.sh) that provisions an Ubuntu VM, installs NGINX, configures a custom HTML homepage, enables firewall rules, and registers the service with systemd.
The Production Script (setup.sh)
#!/usr/bin/env bash
# ==============================================================================
# Script Name: setup.sh
# Description: Automated NGINX Web Server Provisioning
# ==============================================================================
set -euo pipefail
log() {
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] [INFO] $1"
}
# 1. Verify script is run as root
if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root (use sudo)."
exit 1
fi
log "Updating apt package index..."
apt-get update -y > /dev/null
log "Installing NGINX..."
apt-get install -y nginx > /dev/null
log "Deploying custom web application content..."
cat << 'EOF' > /var/www/html/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Platform Architect Lab 1</title>
<style>
body { font-family: sans-serif; background: #0f172a; color: #38bdf8; text-align: center; padding-top: 10%; }
h1 { font-size: 3rem; margin-bottom: 0.5rem; }
p { font-size: 1.25rem; color: #94a3b8; }
</style>
</head>
<body>
<h1>🚀 Hello from NGINX!</h1>
<p>Automated Linux Node Provisioning Verified.</p>
</body>
</html>
EOF
log "Adjusting file ownership and permissions..."
chown -R www-data:www-data /var/www/html
chmod 644 /var/www/html/index.html
log "Enabling and starting NGINX systemd service..."
systemctl enable nginx > /dev/null
systemctl restart nginx
log "Verifying web server response..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:80)
if [[ "${HTTP_STATUS}" -eq 200 ]]; then
log "SUCCESS: NGINX is online and returning HTTP 200!"
else
echo "[ERROR] Health check failed with HTTP status: ${HTTP_STATUS}"
exit 1
fi
Verification Command
🧮 Lab 2: The Subnet Math Challenge
Objective
Given the enterprise VPC block 10.0.0.0/16 ($65,536$ total IP addresses), divide it into 4 equal subnets. Calculate the CIDR prefix, Network ID, Broadcast IP, total IPs, and usable AWS IP ranges for each subnet.
The Mathematical Breakdown
- Original block:
/16(16 network bits, 16 host bits). - To create 4 subnets ($2^2 = 4$), we borrow 2 additional bits from the host portion.
- New Prefix: $16 + 2 = \mathbf{/18}$.
- Total IPs per subnet: $2^{(32 - 18)} = 2^{14} = \mathbf{16,384\text{ IPs}}$.
- AWS Usable IPs: $16,384 - 5 = \mathbf{16,379\text{ IPs}}$.
The Subnet Allocation Table
| Subnet # | CIDR Block | Network ID | First Usable IP (AWS) | Last Usable IP (AWS) | Broadcast Address |
|---|---|---|---|---|---|
| Subnet 1 | 10.0.0.0/18 |
10.0.0.0 |
10.0.0.4 |
10.0.63.254 |
10.0.63.255 |
| Subnet 2 | 10.0.64.0/18 |
10.0.64.0 |
10.0.64.4 |
10.0.127.254 |
10.0.127.255 |
| Subnet 3 | 10.0.128.0/18 |
10.0.128.0 |
10.0.128.4 |
10.0.191.254 |
10.0.191.255 |
| Subnet 4 | 10.0.192.0/18 |
10.0.192.0 |
10.0.192.4 |
10.0.255.254 |
10.0.255.255 |
(Note: In AWS VPCs, .1 is reserved for the VPC Router, .2 for the Amazon DNS Resolver, and .3 for future AWS expansion).
🐳 Lab 3: The Hardened Dockerized Application
Objective
Develop a minimal Python/Flask REST API, package it into a multi-stage Docker container running as an unprivileged user, run it with port mapping, and verify it using curl.
1. Application Code (app.py)
from flask import Flask, jsonify
import socket
import os
app = Flask(__name__)
@Flask.route("/healthz")
def health():
return jsonify({
"status": "healthy",
"hostname": socket.gethostname(),
"environment": os.getenv("APP_ENV", "development")
}), 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
2. Multi-Stage Hardened Dockerfile (Dockerfile)
# Stage 1: Build & Dependencies
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
# Stage 2: Minimal Distroless / Non-Root Runtime
FROM python:3.11-slim
WORKDIR /app
# Security: Create non-root user with UID 10001
RUN useradd -u 10001 -m appuser
# Copy installed python dependencies from builder
COPY --from=builder /root/.local /home/appuser/.local
COPY app.py .
ENV PATH=/home/appuser/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
# Switch to unprivileged user
USER 10001
EXPOSE 8080
CMD ["python", "app.py"]
3. Build & Execution Commands
# 1. Build image
docker build -t platform-api:v1.0.0 .
# 2. Run container mapping host port 8080 to container port 8080
docker run -d -p 8080:8080 -e APP_ENV=production --name test-api platform-api:v1.0.0
# 3. Verify reachability
curl -s http://localhost:8080/healthz | jq .
# 4. Cleanup
docker stop test-api && docker rm test-api