#!/bin/bash # Test 04: Infrastructure Verification # Verifies that docker-compose.yml infrastructure is correctly deployed # Usage: bash labs/lab-02-network/tests/04-verify-infrastructure.sh set -euo pipefail # Color definitions RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' # Get script directory TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LAB_DIR="$(cd "$TEST_DIR/.." && pwd)" # Counter helpers pass_count=0 fail_count=0 inc_pass() { ((pass_count++)) || true; } inc_fail() { ((fail_count++)) || true; } # Helper functions print_header() { echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║${NC} ${BOLD}$1${NC}" echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}" } print_test() { echo -e "\n${BLUE}[TEST]${NC} $1" } print_pass() { echo -e " ${GREEN}[✓]${NC} $1" inc_pass } print_fail() { echo -e " ${RED}[✗]${NC} $1" inc_fail } print_info() { echo -e " ${BLUE}[i]${NC} $1" } # Main verification print_header "Lab 02 Infrastructure Verification" cd "$LAB_DIR" # Test 1: docker-compose.yml exists print_test "Verifying docker-compose.yml exists" if [[ -f "docker-compose.yml" ]]; then print_pass "docker-compose.yml found" else print_fail "docker-compose.yml not found" exit 1 fi # Test 2: docker-compose.yml is valid print_test "Validating docker-compose.yml syntax" if docker compose config &> /dev/null; then print_pass "docker-compose.yml has valid syntax" else print_fail "docker-compose.yml has syntax errors" exit 1 fi # Test 3: Networks are defined print_test "Verifying VPC networks are defined" if docker compose config --format json 2>/dev/null | grep -q '"networks"'; then print_pass "Networks section found in compose file" # Check for vpc-public if docker compose config --format json 2>/dev/null | grep -q '"vpc-public"'; then print_pass " vpc-public network defined" else print_fail " vpc-public network NOT defined" fi # Check for vpc-private if docker compose config --format json 2>/dev/null | grep -q '"vpc-private"'; then print_pass " vpc-private network defined" else print_fail " vpc-private network NOT defined" fi else print_fail "No networks defined" fi # Test 4: INF-02 compliance check print_test "Checking INF-02 compliance (no 0.0.0.0 bindings)" ZERO_BINDINGS=$(grep -c '0\.0\.0\.0:' docker-compose.yml 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 bindings - INF-02 VIOLATION" fi # Test 5: Check for 127.0.0.1 bindings print_test "Checking for localhost-only bindings (127.0.0.1)" LOCALHOST_BINDINGS=$(grep -c '127\.0\.0\.1:' docker-compose.yml 2>/dev/null || echo "0") if [[ $LOCALHOST_BINDINGS -gt 0 ]]; then print_pass "Found $LOCALHOST_BINDINGS localhost-only bindings (secure)" else print_info "No 127.0.0.1 bindings - services may have no published ports" fi # Test 6: Start services print_test "Starting Docker Compose services" if docker compose up -d &> /dev/null; then print_pass "Services started successfully" sleep 3 # Give services time to start else print_fail "Failed to start services" exit 1 fi # Test 7: Verify containers are running print_test "Verifying containers are running" RUNNING_CONTAINERS=$(docker compose ps --services | wc -l) if [[ $RUNNING_CONTAINERS -ge 3 ]]; then print_pass "Services running: $RUNNING_CONTAINERS containers" docker compose ps else print_fail "Not enough containers running: $RUNNING_CONTAINERS (expected 3+)" fi # Test 8: Verify network creation print_test "Verifying VPC networks were created" if docker network ls --format '{{.Name}}' | grep -q "lab02-vpc-public"; then print_pass " lab02-vpc-public network exists" else print_fail " lab02-vpc-public network NOT found" fi if docker network ls --format '{{.Name}}' | grep -q "lab02-vpc-private"; then print_pass " lab02-vpc-private network exists" else print_fail " lab02-vpc-private network NOT found" fi # Test 9: Verify subnet configuration print_test "Verifying subnet CIDR configuration" PUBLIC_SUBNET=$(docker network inspect lab02-vpc-public --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null) PRIVATE_SUBNET=$(docker network inspect lab02-vpc-private --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null) if [[ "$PUBLIC_SUBNET" == "10.0.1.0/24" ]]; then print_pass " Public subnet: $PUBLIC_SUBNET (correct)" else print_fail " Public subnet: $PUBLIC_SUBNET (expected 10.0.1.0/24)" fi if [[ "$PRIVATE_SUBNET" == "10.0.2.0/24" ]]; then print_pass " Private subnet: $PRIVATE_SUBNET (correct)" else print_fail " Private subnet: $PRIVATE_SUBNET (expected 10.0.2.0/24)" fi # Test 10: Verify private network isolation print_test "Verifying private network isolation flag" INTERNAL_FLAG=$(docker network inspect lab02-vpc-private --format '{{.Internal}}' 2>/dev/null) if [[ "$INTERNAL_FLAG" == "true" ]]; then print_pass "Private network has internal=true flag (isolated)" else print_fail "Private network missing internal flag" fi # Test 11: Verify container network placement print_test "Verifying container network placement" if docker inspect lab02-web --format '{{range .NetworkSettings.Networks}}{{.Network}}{{end}}' 2>/dev/null | grep -q "lab02-vpc-public"; then print_pass " lab02-web in vpc-public network" else print_fail " lab02-web not in vpc-public" fi if docker inspect lab02-db --format '{{range .NetworkSettings.Networks}}{{.Network}}{{end}}' 2>/dev/null | grep -q "lab02-vpc-private"; then print_pass " lab02-db in vpc-private network" else print_fail " lab02-db not in vpc-private" fi # Test 12: Verify multi-homed container print_test "Verifying multi-homed container (app in both networks)" PUBLIC_IP=$(docker inspect lab02-app --format '{{range .NetworkSettings.Networks}}{{if eq .Network "lab02-vpc-public"}}{{.IPAddress}}{{end}}{{end}}' 2>/dev/null) PRIVATE_IP=$(docker inspect lab02-app --format '{{range .NetworkSettings.Networks}}{{if eq .Network "lab02-vpc-private"}}{{.IPAddress}}{{end}}{{end}}' 2>/dev/null) if [[ -n "$PUBLIC_IP" && -n "$PRIVATE_IP" ]]; then print_pass "lab02-app is multi-homed (public: $PUBLIC_IP, private: $PRIVATE_IP)" else print_fail "lab02-app not properly connected to both networks" fi # Test 13: Verify web service accessibility print_test "Verifying web service is accessible from localhost" if curl -sf http://127.0.0.1:8080 &> /dev/null; then print_pass "Web service responds on http://127.0.0.1:8080" else print_fail "Web service not accessible on http://127.0.0.1:8080" fi # Test 14: Verify database is NOT accessible from host print_test "Verifying database is NOT accessible from host (private)" if curl -sf http://127.0.0.1:5432 &> /dev/null; then print_fail "Database is accessible from host - PRIVATE NETWORK COMPROMISED!" else print_pass "Database is NOT accessible from host (correct - isolated)" fi # Test 15: Verify isolation between networks print_test "Verifying cross-network isolation (web cannot reach db)" if docker exec lab02-web ping -c 1 -W 1 lab02-db &> /dev/null; then print_fail "Web CAN reach database - ISOLATION FAILED!" else print_pass "Web CANNOT reach database - isolation working correctly" fi # Summary print_header "Infrastructure Verification Summary" echo -e "Tests run: $((pass_count + fail_count))" echo -e "${GREEN}Passed: $pass_count${NC}" if [[ $fail_count -gt 0 ]]; then echo -e "${RED}Failed: $fail_count${NC}" fi if [[ $fail_count -eq 0 ]]; then echo -e "\n${GREEN}${BOLD}✓ ALL INFRASTRUCTURE CHECKS PASSED${NC}" echo -e "\nInfrastructure is correctly deployed and compliant!" echo -e "You can now proceed with the tutorials." exit 0 else echo -e "\n${RED}Some infrastructure checks failed${NC}" echo -e "Please review the failures above." exit 1 fi