--- phase: 02-lab-01-iam-sicurezza plan: 03 type: execute wave: 2 depends_on: [02-01, 02-02] files_modified: - labs/lab-01-iam/Dockerfile - labs/lab-01-iam/docker-compose.yml - labs/lab-01-iam/tests/04-verify-infrastructure.sh autonomous: true requirements: [LAB-01, INF-01, TEST-01] user_setup: [] must_haves: truths: - "docker-compose.yml defines services with non-root user directive (INF-01)" - "Dockerfile creates non-root user and switches before CMD (INF-01)" - "Test scripts validate non-root execution (INF-01)" - "Infrastructure follows test-driven approach (GREEN phase of TDI)" artifacts: - path: "labs/lab-01-iam/Dockerfile" provides: "Non-root container image definition" min_lines: 15 - path: "labs/lab-01-iam/docker-compose.yml" provides: "Service orchestration with user directive" min_lines: 20 - path: "labs/lab-01-iam/tests/04-verify-infrastructure.sh" provides: "Infrastructure verification script" min_lines: 25 key_links: - from: "docker-compose.yml" to: "Dockerfile" via: "build context and image reference" pattern: "build:.*\\..*Dockerfile" - from: "tests/04-verify-infrastructure.sh" to: "docker-compose.yml, Dockerfile" via: "Infrastructure validation" pattern: "docker-compose.*-f.*docker-compose.yml" --- Create Docker infrastructure (Dockerfile and docker-compose.yml) that implements non-root container execution (INF-01). Following TDD methodology, infrastructure is created AFTER tests exist, and tests should now pass (GREEN phase). Purpose: Implement minimum infrastructure to satisfy LAB-01 and INF-01 requirements while ensuring all containers run as non-root. Output: Dockerfile with non-root user, docker-compose.yml with user directive, and infrastructure verification test. @/home/luca/.claude/get-shit-done/workflows/execute-plan.md @/home/luca/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-lab-01-iam-sicurezza/02-RESEARCH.md @.planning/phases/02-lab-01-iam-sicurezza/02-VALIDATION.md @CLAUDE.md # From RESEARCH.md - Non-Root Container Pattern ```dockerfile # Source: Docker security best practices FROM alpine:3.19 # Create non-root user with specific UID/GID for consistency RUN addgroup -g 1000 appgroup && \ adduser -D -u 1000 -G appgroup appuser # Switch to non-root user BEFORE any operations USER appuser # Verify non-root execution CMD ["sh", "-c", "echo 'Running as:' && whoami"] ``` ```yaml # docker-compose.yml with user directive services: test-container: image: alpine:3.19 user: "1000:1000" # UID:GID for non-root command: ["sh", "-c", "whoami && sleep 3600"] ``` # From RESEARCH.md - Verification Methods ```bash # Method 1: Execute whoami inside container docker exec whoami # Expected output: appuser (NOT root) # Method 2: Inspect container configuration docker inspect --format='{{.State.User}}' # Method 3: Check process on host docker top # Look at USER column - should show UID (e.g., 1000), NOT 0 (root) ``` # Common Pitfalls to Avoid - Running containers as root (violates INF-01) - Using `--privileged` flag (defeats container isolation) - Skipping verification of non-root execution - Forgetting `user:` directive in docker-compose.yml # TDD Methodology - GREEN Phase Now that tests exist (Wave 0), implement MINIMUM infrastructure to make them pass: 1. docker-compose.yml with `user:` directive 2. Dockerfile with `USER` directive 3. Run tests to verify GREEN phase 4. Do NOT over-engineer - minimum to pass tests is sufficient Task 1: Create Dockerfile with non-root user labs/lab-01-iam/Dockerfile - Base image: alpine:3.19 (small, secure) - Creates non-root user with UID/GID 1000 - Switches to non-root user with USER directive - CMD demonstrates non-root execution with whoami - Follows INF-01 requirement (no root execution) Create Dockerfile that implements non-root container execution: ```dockerfile # Lab 01 - IAM & Sicurezza # Dockerfile per container non-root (INF-01 requirement) # # Questo Dockerfile dimostra come creare un container che gira # come utente non-root, seguendo il principio del minimo privilegio. FROM alpine:3.19 # Label per metadata LABEL maintainer="Lab 01 - IAM & Sicurezza" LABEL description="Container non-root per dimostrare permessi IAM" LABEL version="1.0" # Crea utente non-root con UID/GID specifici per consistenza # UID 1000 e GID 1000 sono comuni per utenti non-root RUN addgroup -g 1000 labuser && \ adduser -D -u 1000 -G labuser labuser # Imposta la working directory (creata con adduser -D) WORKDIR /home/labuser # Crea un file semplice per verificare i permessi di scrittura RUN echo "Questo file e stato creato durante la build" > /home/labuser/test.txt && \ chown labuser:labuser /home/labuser/test.txt # PASSA A UTENTE NON-ROOT PRIMA DI QUALSIASI OPERAZIONE # Questo e il punto chiave per INF-01: nessun processo gira come root USER labuser # Verifica che il container gira come utente non-root CMD ["sh", "-c", "\ echo '========================================' && \ echo 'Lab 01 - IAM & Sicurezza' && \ echo 'Container non-root verification (INF-01)' && \ echo '========================================' && \ echo '' && \ echo 'Utente corrente:' && \ whoami && \ echo '' && \ echo 'UID:' && \ id -u && \ echo '' && \ echo 'GID:' && \ id -g && \ echo '' && \ echo 'Gruppi:' && \ groups && \ echo '' && \ echo 'Home directory:' && \ pwd && \ echo '' && \ echo 'Contenuto di test.txt (permessi scrittura):' && \ cat test.txt && \ echo '' && \ echo '========================================' && \ echo 'Se vedi \"labuser\" sopra, INF-01 e soddisfatto!' && \ echo '========================================' && \ echo '' && \ echo 'Container in esecuzione. Premi Ctrl-C per uscire.' && \ sleep 3600 \ "] ``` Key implementation points: - Base image Alpine 3.19 (minimal, secure) - Creates `labuser` with UID/GID 1000 - USER directive switches to non-root BEFORE CMD - CMD demonstrates and verifies non-root execution - Follows INF-01 requirement strictly - Labels for metadata and documentation - Working directory set to user's home - Test file to verify write permissions TDD Context: This is the GREEN phase - tests already exist (from Wave 0), this Dockerfile should make those tests pass. cd labs/lab-01-iam && docker build -t lab01-non-root . && docker run --rm lab01-non-root | grep -q "labuser" && echo "PASS: Container runs as non-root" || echo "FAIL: Container not running as labuser" Dockerfile creates non-root container verified by whoami output Task 2: Create docker-compose.yml with user directive labs/lab-01-iam/docker-compose.yml - Defines service with local image build - Specifies user directive (1000:1000) for non-root execution - Includes container_name for easy reference - Follows INF-01 requirement (no root) - Enables test scripts to verify configuration Create docker-compose.yml that enforces non-root execution: ```yaml # Lab 01 - IAM & Sicurezza # Docker Compose configuration per container non-root # # Questo file definisce i servizi per il lab, assicurandosi che # TUTTI i container girino come utente non-root (INF-01). version: "3.8" services: # Container di test per verificare l'esecuzione non-root lab01-test: build: context: . dockerfile: Dockerfile image: lab01-non-root:latest container_name: lab01-iam-test # CRITICO: user directive assicura esecuzione non-root (INF-01) # Format: UID:GID # 1000:1000 corrisponde all'utente labuser creato nel Dockerfile user: "1000:1000" # Non esponiamo porte (non necessario per questo lab) # Le porte private non devono essere esposte sull'host (best practice) restart: unless-stopped # Nessun volume mount necessario per questo lab semplice # I volumi saranno introdotti nei lab successivi healthcheck: # Healthcheck per verificare che il container sia sano test: ["CMD", "sh", "-c", "whoami | grep -q labuser"] interval: 30s timeout: 5s retries: 3 start_period: 5s # Nessuna rete definita - useremo la default bridge network # Le reti custom isolate saranno introdotte nel Lab 02 (Network & VPC) # Nessun volume definito - i volumi saranno introdotti nel Lab 04 (Storage & S3) ``` Key implementation points: - Service definition with local build context - `user: "1000:1000"` directive enforces non-root execution - Container name matches test expectations - Healthcheck verifies non-root user - Comments explain why no volumes/networks (future labs) - Follows docker-compose V3.8 syntax - No ports exposed (security best practice) TDD Context: Tests from Wave 0 check for user directive - this configuration should satisfy those tests. INF-01 Compliance: - User directive explicitly set - Healthcheck verifies non-root execution - No possibility of root execution cd labs/lab-01-iam && docker-compose config > /dev/null 2>&1 && echo "PASS: docker-compose.yml is valid" || echo "FAIL: docker-compose.yml has errors" docker-compose.yml defines service with non-root user directive Task 3: Create infrastructure verification script labs/lab-01-iam/tests/04-verify-infrastructure.sh - Test 1: docker-compose.yml is valid YAML - Test 2: Dockerfile builds successfully - Test 3: Service has user directive set - Test 4: Built container runs as non-root - Test 5: All INF-01 requirements satisfied Create infrastructure verification script (TDD GREEN phase verification): ```bash #!/bin/bash # Infrastructure Verification: Lab 01 # Verifies that docker-compose.yml and Dockerfile satisfy all requirements # This is the GREEN phase check - tests should pass after infrastructure implementation set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$TEST_DIR/../.." && pwd)" LAB_DIR="$PROJECT_ROOT/labs/lab-01-iam" cd "$LAB_DIR" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}Lab 01 Infrastructure Verification${NC}" echo -e "${BLUE}GREEN Phase Check${NC}" echo -e "${BLUE}========================================${NC}" echo "" pass_count=0 fail_count=0 # Test 1: docker-compose.yml is valid echo -e "${BLUE}[1/6] Checking docker-compose.yml syntax...${NC}" if docker-compose config >/dev/null 2>&1; then echo -e " ${GREEN}✓${NC} docker-compose.yml is valid YAML" ((pass_count++)) else echo -e " ${RED}✗${NC} docker-compose.yml has syntax errors" ((fail_count++)) fi echo "" # Test 2: Dockerfile exists and is readable echo -e "${BLUE}[2/6] Checking Dockerfile...${NC}" if [ -f "Dockerfile" ]; then echo -e " ${GREEN}✓${NC} Dockerfile exists" # Check for USER directive if grep -q "^USER" Dockerfile; then user_line=$(grep "^USER" Dockerfile) echo -e " ${GREEN}✓${NC} USER directive found: $user_line" ((pass_count++)) else echo -e " ${RED}✗${NC} No USER directive found in Dockerfile" ((fail_count++)) fi else echo -e " ${RED}✗${NC} Dockerfile not found" ((fail_count++)) fi echo "" # Test 3: docker-compose.yml has user directive echo -e "${BLUE}[3/6] Checking docker-compose.yml user directive...${NC}" if grep -q "user:" docker-compose.yml; then user_value=$(grep "user:" docker-compose.yml | head -1 | sed 's/.*user: *//' | tr -d '"') echo -e " ${GREEN}✓${NC} user directive found: $user_value" # Verify it's not root (0:0) if [[ "$user_value" != *"0:0"* ]] && [[ "$user_value" != *"root"* ]]; then echo -e " ${GREEN}✓${NC} User is not root (INF-01 compliant)" ((pass_count++)) else echo -e " ${RED}✗${NC} User is root (INF-01 violation)" ((fail_count++)) fi else echo -e " ${RED}✗${NC} No user directive in docker-compose.yml" ((fail_count++)) fi echo "" # Test 4: Build Docker image echo -e "${BLUE}[4/6] Building Docker image...${NC}" if docker build -t lab01-non-root -q Dockerfile >/dev/null 2>&1; then echo -e " ${GREEN}✓${NC} Docker image built successfully" ((pass_count++)) else echo -e " ${RED}✗${NC} Docker image build failed" ((fail_count++)) fi echo "" # Test 5: Verify container runs as non-root echo -e "${BLUE}[5/6] Verifying non-root execution...${NC}" if docker run --rm lab01-non-root whoami 2>/dev/null | grep -q "labuser"; then echo -e " ${GREEN}✓${NC} Container runs as non-root user (labuser)" ((pass_count++)) else echo -e " ${RED}✗${NC} Container not running as labuser" ((fail_count++)) fi echo "" # Test 6: Verify docker-compose service echo -e "${BLUE}[6/6] Verifying docker-compose service...${NC}" # Start container in detached mode if docker-compose up -d >/dev/null 2>&1; then echo -e " ${GREEN}✓${NC} docker-compose service started" # Wait for container to be ready sleep 3 # Check container is running if docker ps --format "{{.Names}}" | grep -q "^lab01-iam-test$"; then echo -e " ${GREEN}✓${NC} Container is running" # Verify user actual_user=$(docker exec lab01-iam-test whoami 2>/dev/null || echo "unknown") if [ "$actual_user" = "labuser" ]; then echo -e " ${GREEN}✓${NC} docker-compose container runs as non-root" ((pass_count++)) else echo -e " ${RED}✗${NC} docker-compose container running as $actual_user (expected labuser)" ((fail_count++)) fi else echo -e " ${RED}✗${NC} Container not running" ((fail_count++)) fi # Cleanup docker-compose down --volumes >/dev/null 2>&1 else echo -e " ${RED}✗${NC} Failed to start docker-compose service" ((fail_count++)) fi echo "" # Summary echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}Verification Summary${NC}" echo -e "${BLUE}========================================${NC}" echo "Passed: $pass_count/6" echo "Failed: $fail_count/6" echo "" if [ $fail_count -eq 0 ]; then echo -e "${GREEN}All checks passed!${NC}" echo -e "${GREEN}GREEN phase complete - infrastructure satisfies tests${NC}" echo "" echo "Next: Run full test suite" echo " bash labs/lab-01-iam/tests/run-all-tests.sh" echo -e "${BLUE}========================================${NC}" exit 0 else echo -e "${RED}Some checks failed${NC}" echo -e "${RED}Infrastructure needs fixes before tests will pass${NC}" echo -e "${BLUE}========================================${NC}" exit 1 fi ``` Key implementation points: - Validates docker-compose.yml syntax - Verifies USER directive in Dockerfile - Verifies user directive in docker-compose.yml - Builds and tests Docker image - Starts container with docker-compose and verifies execution - Proper cleanup after testing - Clear pass/fail indicators TDD Context: This script confirms the GREEN phase - infrastructure implementation makes tests pass. chmod +x labs/lab-01-iam/tests/04-verify-infrastructure.sh && cd labs/lab-01-iam && bash ../tests/04-verify-infrastructure.sh Infrastructure verification script confirms all requirements satisfied 1. Dockerfile creates non-root user with USER directive 2. docker-compose.yml specifies user directive for service 3. docker-compose config validates without errors 4. Docker build succeeds without warnings 5. Container execution verified as non-root (whoami, docker inspect, docker top) 6. All Wave 0 tests now pass (GREEN phase of TDD) 7. INF-01 requirement satisfied: no container runs as root 1. Dockerfile follows non-root best practices from RESEARCH.md 2. docker-compose.yml enforces non-root execution via user directive 3. Infrastructure verification confirms all requirements met 4. Tests from Wave 0 (02-01-PLAN.md) now pass 5. LAB-01 requirement satisfied: students can configure users and Docker permissions 6. INF-01 requirement satisfied: no container runs as root After completion, create `.planning/phases/02-lab-01-iam-sicurezza/02-03-SUMMARY.md`