#!/bin/bash # Test 02: Isolation Verification # Validates network isolation between Docker bridge networks # Usage: bash labs/lab-02-network/tests/02-isolation-verification-test.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)" # Counter helpers pass_count=0 fail_count=0 skip_count=0 inc_pass() { ((pass_count++)) || true; } inc_fail() { ((fail_count++)) || true; } inc_skip() { ((skip_count++)) || true; } # Test helper functions print_header() { echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" } print_test() { echo -e "\n${BLUE}[TEST]${NC} $1" } print_pass() { echo -e "${GREEN}[PASS]${NC} $1" inc_pass } print_fail() { echo -e "${RED}[FAIL]${NC} $1" inc_fail } print_skip() { echo -e "${YELLOW}[SKIP]${NC} $1" inc_skip } print_info() { echo -e "${BLUE}[INFO]${NC} $1" } # Cleanup function cleanup() { echo -e "\n${BLUE}[*] Cleaning up test containers and networks...${NC}" # Stop and remove containers for container in c1 c2 c3 c4; do docker stop "$container" 2>/dev/null || true docker rm "$container" 2>/dev/null || true done # Remove networks for network in test-net1 test-net2 test-isolated-net; do docker network rm "$network" 2>/dev/null || true done echo -e "${GREEN}[✓] Cleanup complete${NC}" } # Set trap for cleanup trap cleanup EXIT # Start testing print_header "Lab 02 - Test 02: Network Isolation Verification" # Test 1: Create two isolated networks print_test "Test 1: Create two isolated bridge networks (10.0.1.0/24 and 10.0.2.0/24)" if docker network create --driver bridge --subnet 10.0.1.0/24 --gateway 10.0.1.1 test-net1 &> /dev/null && \ docker network create --driver bridge --subnet 10.0.2.0/24 --gateway 10.0.2.1 test-net2 &> /dev/null; then print_pass "Created two isolated networks successfully" docker network ls --filter "name=test-net" --format "table {{.Name}}\t{{.Driver}}\t{{.Scope}}" else print_fail "Failed to create test networks" exit 1 fi # Test 2: Create containers in same network print_test "Test 2: Create containers in the same network (test-net1)" if docker run -d --name c1 --network test-net1 --hostname c1 alpine:3.19 sleep 3600 &> /dev/null && \ docker run -d --name c2 --network test-net1 --hostname c2 alpine:3.19 sleep 3600 &> /dev/null; then print_pass "Created containers c1 and c2 in test-net1" docker ps --filter "name=c[12]" --format "table {{.Names}}\t{{.Networks}}\t{{.Status}}" else print_fail "Failed to create containers in test-net1" exit 1 fi # Test 3: Containers in same network CAN communicate (ping should succeed) print_test "Test 3: Containers in same network can communicate (ping test)" if docker exec c1 ping -c 2 -W 1 c2 &> /dev/null; then print_pass "c1 can successfully ping c2 (same-network communication works)" docker exec c1 ping -c 2 -W 1 c2 | grep "packets transmitted" else print_fail "c1 cannot ping c2 (same-network communication should work)" fi # Test 4: Containers in same network can resolve by DNS name print_test "Test 4: Containers in same network can resolve each other by DNS name" if docker exec c1 nslookup c2 &> /dev/null; then print_pass "DNS resolution works within same network" docker exec c1 nslookup c2 | grep "Address" | head -1 else print_fail "DNS resolution failed within same network" fi # Test 5: Create container in different network print_test "Test 5: Create container c3 in different network (test-net2)" if docker run -d --name c3 --network test-net2 --hostname c3 alpine:3.19 sleep 3600 &> /dev/null; then print_pass "Created container c3 in isolated network test-net2" print_info "c1 and c2 are in test-net1, c3 is in test-net2 (isolated)" else print_fail "Failed to create container c3 in test-net2" exit 1 fi # Test 6: Containers in DIFFERENT networks CANNOT communicate (isolation test) print_test "Test 6: Containers in different networks CANNOT communicate (isolation verification)" print_info "This test EXPECTS ping to FAIL (proves isolation works)" if docker exec c1 ping -c 2 -W 1 c3 &> /dev/null; then print_fail "c1 CAN ping c3 - ISOLATION FAILED! Networks are not isolated!" print_fail "This is a security issue - containers should not reach across networks" else print_pass "c1 CANNOT ping c3 - Network isolation is working correctly!" print_info "This is the expected behavior - isolation prevents cross-network communication" fi # Test 7: Cross-network DNS resolution should fail print_test "Test 7: Cross-network DNS resolution should fail" print_info "This test EXPECTS DNS lookup to FAIL (proves DNS isolation)" if docker exec c1 nslookup c3 &> /dev/null; then print_fail "c1 CAN resolve c3 by DNS - DNS isolation FAILED!" else print_pass "c1 CANNOT resolve c3 - DNS isolation is working correctly!" fi # Test 8: Create a container connected to both networks (multi-homed) print_test "Test 8: Create multi-homed container c4 connected to BOTH networks" if docker run -d --name c4 --network test-net1 alpine:3.19 sleep 3600 &> /dev/null && \ docker network connect test-net2 c4 &> /dev/null; then print_pass "Created container c4 connected to both networks" docker inspect c4 --format 'Networks: {{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{end}}' else print_fail "Failed to create multi-homed container" fi # Test 9: Multi-homed container can reach containers in both networks print_test "Test 9: Multi-homed container c4 can reach both c1 (net1) and c3 (net2)" c4_to_c1_result=$(docker exec c4 ping -c 1 -W 1 c1 &> /dev/null && echo "OK" || echo "FAIL") c4_to_c3_result=$(docker exec c4 ping -c 1 -W 1 c3 &> /dev/null && echo "OK" || echo "FAIL") if [[ "$c4_to_c1_result" == "OK" && "$c4_to_c3_result" == "OK" ]]; then print_pass "Multi-homed container can reach both networks (c4->c1: OK, c4->c3: OK)" else print_fail "Multi-homed container connectivity issue (c4->c1: $c4_to_c1_result, c4->c3: $c4_to_c3_result)" fi # Test 10: Verify isolation still works - c1 cannot ping c3 despite c4 being multi-homed print_test "Test 10: Verify isolation - c1 still cannot reach c3 (despite c4 bridging networks)" if docker exec c1 ping -c 1 -W 1 c3 &> /dev/null; then print_fail "c1 CAN ping c3 - ISOLATION BROKEN! Multi-homing created a bridge!" else print_pass "Isolation maintained - c1 still cannot reach c3 (multi-homing doesn't break isolation)" fi # Test 11: Create isolated internal network print_test "Test 11: Create internal network (no external access)" if docker network create --driver bridge --internal --subnet 10.0.10.0/24 test-isolated-net &> /dev/null; then print_pass "Created internal network test-isolated-net" docker network inspect test-isolated-net --format 'Internal: {{.Internal}}' else print_fail "Failed to create internal network" fi # Test 12: Verify container in internal network cannot reach external internet print_test "Test 12: Container in internal network cannot reach external internet" docker run -d --name isolated-test --network test-isolated-net alpine:3.19 sleep 3600 &> /dev/null || true if docker exec isolated-test ping -c 1 -W 1 8.8.8.8 &> /dev/null; then print_fail "Container in internal network CAN reach internet - internal flag not working!" else print_pass "Container in internal network CANNOT reach internet (isolation works)" print_info "This is expected behavior for --internal flag networks" fi # Cleanup isolated test container early docker stop isolated-test &> /dev/null || true docker rm isolated-test &> /dev/null || true # Test 13: Verify network IP addresses don't overlap print_test "Test 13: Verify network subnets are properly isolated (no IP overlap)" net1_subnet=$(docker network inspect test-net1 --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || echo "") net2_subnet=$(docker network inspect test-net2 --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || echo "") if [[ "$net1_subnet" != "$net2_subnet" ]]; then print_pass "Network subnets are different (no overlap)" echo " test-net1: $net1_subnet" echo " test-net2: $net2_subnet" else print_fail "Network subnets are identical - IP overlap will occur!" fi # Test 14: Verify containers have IPs from correct subnets print_test "Test 14: Verify containers have IPs from their network's subnet" c1_ip=$(docker inspect c1 --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2>/dev/null || echo "") c3_ip=$(docker inspect c3 --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2>/dev/null || echo "") c1_in_net1=$(echo "$c1_ip" | grep -q "^10.0.1." && echo "yes" || echo "no") c3_in_net2=$(echo "$c3_ip" | grep -q "^10.0.2." && echo "yes" || echo "no") if [[ "$c1_in_net1" == "yes" && "$c3_in_net2" == "yes" ]]; then print_pass "Containers have IPs from correct subnets" echo " c1 IP: $c1_ip (should be in 10.0.1.0/24)" echo " c3 IP: $c3_ip (should be in 10.0.2.0/24)" else print_fail "Container IPs don't match expected subnets" echo " c1 IP: $c1_ip (expected 10.0.1.x)" echo " c3 IP: $c3_ip (expected 10.0.2.x)" fi # Summary print_header "Test Summary" echo -e "Total tests run: $((pass_count + fail_count + skip_count))" echo -e "${GREEN}Passed: $pass_count${NC}" if [[ $fail_count -gt 0 ]]; then echo -e "${RED}Failed: $fail_count${NC}" fi if [[ $skip_count -gt 0 ]]; then echo -e "${YELLOW}Skipped: $skip_count${NC}" fi # Isolation verification message echo -e "\n${BLUE}[*] Network Isolation Summary${NC}" echo -e "Same-network communication: ${GREEN}WORKS${NC} (expected)" echo -e "Cross-network communication: ${GREEN}BLOCKED${NC} (isolation working)" echo -e "DNS isolation: ${GREEN}ENFORCED${NC} (cross-network DNS blocked)" echo -e "Internal network isolation: ${GREEN}ENFORCED${NC} (no external access)" # Exit with error code if any tests failed if [[ $fail_count -gt 0 ]]; then echo -e "\n${RED}Some tests failed. Please review the output above.${NC}" exit 1 else echo -e "\n${GREEN}All tests passed! Network isolation is working correctly.${NC}" exit 0 fi