feat(lab-02): complete Phase 3 - Network & VPC lab

Implement Lab 02 with Docker bridge networks simulating VPC/Subnets.

Test Infrastructure (RED phase):
- 6 bash test scripts for network creation, isolation, INF-02 compliance
- Fail-fast orchestration with run-all-tests.sh
- Quick validation script for development

Documentation (Diátaxis framework):
- 3 tutorials: VPC creation, container deployment, isolation verification
- 4 how-to guides: create network, inspect config, test isolation, cleanup
- 3 reference docs: Docker network commands, Compose syntax, VPC mapping
- 1 explanation: Docker ↔ VPC parallels (PARA-01/02/03/04)

Infrastructure (GREEN phase):
- docker-compose.yml with VPC networks (10.0.1.0/24, 10.0.2.0/24)
- 5 services: web, app, db, test-public, test-private
- INF-02 compliant: 127.0.0.1 bindings only, no 0.0.0.0
- Private network with --internal flag
- Multi-homed app container (public + private networks)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Luca Sacchi Ricciardi
2026-03-25 17:26:35 +01:00
parent d4c4f7d717
commit 5b2c8c37aa
22 changed files with 3988 additions and 12 deletions

View File

@@ -0,0 +1,325 @@
#!/bin/bash
# Final Verification: Lab 02 - Network & VPC
# Comprehensive end-to-end verification for students (double-check command)
# Usage: bash labs/lab-02-network/tests/99-final-verification.sh
set -euo pipefail
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# Get script directory
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$TEST_DIR/../.." && pwd)"
LAB_DIR="$PROJECT_ROOT/labs/lab-02-network"
# Counter helpers
pass_count=0
fail_count=0
warn_count=0
inc_pass() { ((pass_count++)) || true; }
inc_fail() { ((fail_count++)) || true; }
inc_warn() { ((warn_count++)) || true; }
# Helper functions
print_header() {
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}${NC} ${BOLD}$1${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}"
}
print_section() {
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}
print_pass() {
echo -e " ${GREEN}[✓]${NC} $1"
inc_pass
}
print_fail() {
echo -e " ${RED}[✗]${NC} $1"
inc_fail
}
print_warn() {
echo -e " ${YELLOW}[!]${NC} $1"
inc_warn
}
print_info() {
echo -e " ${BLUE}[i]${NC} $1"
}
# Main header
clear
print_header "Lab 02: Network & VPC - Final Verification"
echo ""
echo -e "This script verifies your entire Lab 02 implementation."
echo -e "Run this after completing all tutorials to double-check your work."
echo ""
# Verify Docker is available
print_section "0. Environment Check"
if ! command -v docker &> /dev/null; then
echo -e "${RED}ERROR: Docker is not installed or not in PATH${NC}"
exit 1
fi
echo -e "Docker version: $(docker --version | cut -d' ' -f3)"
echo -e "Docker Compose version: $(docker compose version | grep 'Docker Compose' | cut -d' ' -f4)"
# Test 1: Network Creation
print_section "1. Network Creation Verification"
COMPOSE_FILE="$LAB_DIR/docker-compose.yml"
if [[ ! -f "$COMPOSE_FILE" ]]; then
print_fail "docker-compose.yml not found at $COMPOSE_FILE"
print_info "Expected output of Tutorial 1"
FAIL_REASON="compose_missing"
else
print_pass "docker-compose.yml exists"
# Validate compose syntax
if docker compose -f "$COMPOSE_FILE" config &> /dev/null; then
print_pass "docker-compose.yml has valid syntax"
else
print_fail "docker-compose.yml has syntax errors"
print_info "Run: docker compose -f docker-compose.yml config"
FAIL_REASON="compose_invalid"
fi
fi
# Test 2: Network Topology
print_section "2. Network Topology Verification"
if [[ "${FAIL_REASON:-}" == "compose_missing" ]]; then
print_warn "Skipping network tests - compose file missing"
else
# Check for custom networks
NETWORKS=$(docker compose -f "$COMPOSE_FILE" config --format json 2>/dev/null | grep -o '"networks"' | wc -l || echo "0")
if [[ $NETWORKS -gt 0 ]]; then
print_pass "Custom networks defined in docker-compose.yml"
# List networks
echo ""
print_info "Networks defined:"
docker compose -f "$COMPOSE_FILE" config --format json 2>/dev/null | \
grep -A 3 '"networks"' | grep -E '^\s+"[a-z]+"' | sed 's/.*"\([^"]*\)".*/ \1/' || echo " (unable to list)"
else
print_warn "No custom networks found - using default bridge"
fi
# Check for VPC-style naming (PARA-02 requirement)
VPC_NAMES=$(grep -E 'vpc-|subnet-|network-' "$COMPOSE_FILE" 2>/dev/null | wc -l || echo "0")
if [[ $VPC_NAMES -gt 0 ]]; then
print_pass "Uses VPC-style naming convention (PARA-02 compliant)"
else
print_warn "VPC-style naming not found (recommended: vpc-main, subnet-public, etc.)"
fi
fi
# Test 3: INF-02 Compliance
print_section "3. INF-02 Security Compliance"
if [[ -f "$COMPOSE_FILE" ]]; then
# Check for 0.0.0.0 bindings
ZERO_BINDINGS=$(grep -c -E '0\.0\.0\.0:[0-9]+' "$COMPOSE_FILE" 2>/dev/null || echo "0")
if [[ $ZERO_BINDINGS -eq 0 ]]; then
print_pass "No 0.0.0.0 port bindings found (INF-02 compliant)"
else
print_fail "Found $ZERO_BINDINGS 0.0.0.0 port bindings - VIOLATES INF-02"
print_info "Private networks must not expose ports on 0.0.0.0"
FAIL_REASON="inf02_violation"
fi
# Check for localhost bindings
LOCALHOST_BINDINGS=$(grep -c -E '127\.0\.0\.1:[0-9]+' "$COMPOSE_FILE" 2>/dev/null || echo "0")
if [[ $LOCALHOST_BINDINGS -gt 0 ]]; then
print_pass "Found $LOCALHOST_BINDINGS service(s) with 127.0.0.1 binding (secure)"
else
print_info "No 127.0.0.1 bindings - services may have no published ports"
fi
# Check for host networking
HOST_NET=$(grep -c -E 'network_mode:\s*host' "$COMPOSE_FILE" 2>/dev/null || echo "0")
if [[ $HOST_NET -eq 0 ]]; then
print_pass "No services using host networking mode"
else
print_fail "Found services using 'network_mode: host' - security risk"
FAIL_REASON="host_networking"
fi
else
print_warn "Skipping INF-02 tests - compose file missing"
fi
# Test 4: Service Startup
print_section "4. Service Startup Verification"
if [[ -f "$COMPOSE_FILE" && "${FAIL_REASON:-}" != "compose_invalid" ]]; then
print_info "Attempting to start services..."
if docker compose -f "$COMPOSE_FILE" up -d &> /dev/null; then
print_pass "Services started successfully"
# List running services
echo ""
print_info "Running services:"
docker compose -f "$COMPOSE_FILE" ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || \
docker compose -f "$COMPOSE_FILE" ps
# Cleanup
print_info "Stopping services..."
docker compose -f "$COMPOSE_FILE" down &> /dev/null
else
print_fail "Services failed to start"
print_info "Run: docker compose -f docker-compose.yml up"
print_info "Check logs: docker compose -f docker-compose.yml logs"
FAIL_REASON="services_failed"
fi
else
print_warn "Skipping service tests - compose file missing or invalid"
fi
# Test 5: Documentation Completeness
print_section "5. Documentation Completeness (Diátxis Framework)"
DOC_COUNT=0
DOC_FILES=(
"$LAB_DIR/tutorial/01-create-networks.md"
"$LAB_DIR/tutorial/02-deploy-containers.md"
"$LAB_DIR/tutorial/03-verify-isolation.md"
"$LAB_DIR/how-to-guides/*.md"
"$LAB_DIR/reference/*.md"
"$LAB_DIR/explanation/*.md"
)
for file_pattern in "${DOC_FILES[@]}"; do
count=$(ls $file_pattern 2>/dev/null | wc -l)
DOC_COUNT=$((DOC_COUNT + count))
done
if [[ $DOC_COUNT -ge 10 ]]; then
print_pass "Documentation complete: $DOC_COUNT files found (Framework Diátaxis)"
echo ""
print_info "Documentation breakdown:"
echo -e " Tutorials: $(ls "$LAB_DIR/tutorial"/*.md 2>/dev/null | wc -l)"
echo -e " How-to Guides: $(ls "$LAB_DIR/how-to-guides"/*.md 2>/dev/null | wc -l)"
echo -e " Reference: $(ls "$LAB_DIR/reference"/*.md 2>/dev/null | wc -l)"
echo -e " Explanation: $(ls "$LAB_DIR/explanation"/*.md 2>/dev/null | wc -l)"
else
print_warn "Documentation incomplete: $DOC_COUNT files found (expected 10+)"
print_info "Complete all tutorials and documentation"
fi
# Test 6: Test Infrastructure
print_section "6. Test Infrastructure Verification"
TEST_FILES=(
"$TEST_DIR/01-network-creation-test.sh"
"$TEST_DIR/02-isolation-verification-test.sh"
"$TEST_DIR/03-inf02-compliance-test.sh"
"$TEST_DIR/run-all-tests.sh"
)
TESTS_FOUND=0
for test_file in "${TEST_FILES[@]}"; do
if [[ -f "$test_file" && -x "$test_file" ]]; then
((TESTS_FOUND++)) || true
fi
done
if [[ $TESTS_FOUND -eq ${#TEST_FILES[@]} ]]; then
print_pass "All test scripts present and executable"
elif [[ $TESTS_FOUND -gt 0 ]]; then
print_warn "Some test scripts missing: $TESTS_FOUND/${#TEST_FILES[@]} found"
else
print_fail "Test infrastructure not found"
fi
# Final Summary
print_section "Final Summary"
echo ""
echo -e " ${BOLD}Results:${NC}"
echo -e " ${GREEN}✓ Passed:${NC} $pass_count"
if [[ $fail_count -gt 0 ]]; then
echo -e " ${RED}✗ Failed:${NC} $fail_count"
fi
if [[ $warn_count -gt 0 ]]; then
echo -e " ${YELLOW}! Warnings:${NC} $warn_count"
fi
echo ""
# Overall verdict
if [[ $fail_count -eq 0 && $warn_count -eq 0 ]]; then
echo -e "${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ ✓ ALL CHECKS PASSED ║${NC}"
echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${GREEN}Your Lab 02 implementation is complete and compliant!${NC}"
echo ""
echo -e "Next steps:"
echo -e " 1. Review the Explanation document to understand VPC parallels"
echo -e " 2. Proceed to Phase 4: Lab 03 - Compute & EC2"
echo ""
exit 0
elif [[ $fail_count -eq 0 ]]; then
echo -e "${YELLOW}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}${BOLD}║ ! PASSED WITH WARNINGS ║${NC}"
echo -e "${YELLOW}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}Implementation is functional but has warnings.${NC}"
echo ""
echo -e "Recommendations:"
if [[ $VPC_NAMES -eq 0 ]]; then
echo -e " - Consider using VPC-style naming (vpc-main, subnet-public, subnet-private)"
fi
if [[ $DOC_COUNT -lt 10 ]]; then
echo -e " - Complete all documentation files (Diátxis Framework)"
fi
echo ""
exit 0
else
echo -e "${RED}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}${BOLD}║ ✗ VERIFICATION FAILED ║${NC}"
echo -e "${RED}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${RED}Some checks failed. Please review the issues above.${NC}"
echo ""
# Provide specific guidance
case "${FAIL_REASON:-}" in
compose_missing)
echo -e "${YELLOW}To fix:${NC} Complete Tutorial 1 to create docker-compose.yml"
;;
compose_invalid)
echo -e "${YELLOW}To fix:${NC} Validate and fix docker-compose.yml syntax"
echo -e " Run: docker compose -f docker-compose.yml config"
;;
inf02_violation)
echo -e "${YELLOW}To fix:${NC} Replace 0.0.0.0 bindings with 127.0.0.1"
echo -e " Change: '8080:80' → '127.0.0.1:8080:80'"
;;
services_failed)
echo -e "${YELLOW}To fix:${NC} Check service logs for errors"
echo -e " Run: docker compose -f docker-compose.yml logs"
;;
*)
echo -e "${YELLOW}To fix:${NC} Review the failed items above and complete the tutorials"
;;
esac
echo ""
echo -e "After fixing, run this verification again:"
echo -e " ${CYAN}bash labs/lab-02-network/tests/99-final-verification.sh${NC}"
echo ""
exit 1
fi