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:
241
labs/lab-02-network/tests/04-verify-infrastructure.sh
Executable file
241
labs/lab-02-network/tests/04-verify-infrastructure.sh
Executable file
@@ -0,0 +1,241 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user