Files
2026-03-24 21:55:00 +01:00

17 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
02-lab-01-iam-sicurezza 03 execute 2
02-01
02-02
labs/lab-01-iam/Dockerfile
labs/lab-01-iam/docker-compose.yml
labs/lab-01-iam/tests/04-verify-infrastructure.sh
true
LAB-01
INF-01
TEST-01
truths artifacts key_links
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)
path provides min_lines
labs/lab-01-iam/Dockerfile Non-root container image definition 15
path provides min_lines
labs/lab-01-iam/docker-compose.yml Service orchestration with user directive 20
path provides min_lines
labs/lab-01-iam/tests/04-verify-infrastructure.sh Infrastructure verification script 25
from to via pattern
docker-compose.yml Dockerfile build context and image reference build:.*..*Dockerfile
from to via pattern
tests/04-verify-infrastructure.sh docker-compose.yml, Dockerfile Infrastructure validation 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.

<execution_context> @/home/luca/.claude/get-shit-done/workflows/execute-plan.md @/home/luca/.claude/get-shit-done/templates/summary.md </execution_context>

@.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

# 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"]
# 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

# Method 1: Execute whoami inside container
docker exec <container_name> whoami
# Expected output: appuser (NOT root)

# Method 2: Inspect container configuration
docker inspect <container_name> --format='{{.State.User}}'

# Method 3: Check process on host
docker top <container_name>
# 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:
# 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:
# 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):
#!/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

<success_criteria>

  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 </success_criteria>
After completion, create `.planning/phases/02-lab-01-iam-sicurezza/02-03-SUMMARY.md`