#!/usr/bin/env bash # # Phase 3 Validation: DNS and Email # # Validates that RFC 0041 components are deployed and healthy: # - PowerDNS (responding, DNSSEC enabled) # - Stalwart (SMTP, IMAP, TLS) # - DNS records (SPF, DKIM, DMARC) # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' PASSED=0 FAILED=0 WARNINGS=0 # Configuration DOMAIN="${DOMAIN:-coherence.dev}" log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_pass() { echo -e "${GREEN}[PASS]${NC} $1" ((PASSED++)) } log_fail() { echo -e "${RED}[FAIL]${NC} $1" ((FAILED++)) } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" ((WARNINGS++)) } check_powerdns() { log_info "Checking PowerDNS status..." # Check if namespace exists if ! kubectl get namespace dns &> /dev/null; then log_fail "dns namespace does not exist" return fi # Check pod health local ready_pods ready_pods=$(kubectl -n dns get pods -l app=powerdns -o json | jq '[.items[] | select(.status.phase == "Running") | select(.status.containerStatuses[]?.ready == true)] | length') if [ "$ready_pods" -ge 1 ]; then log_pass "PowerDNS has $ready_pods ready pods" else log_fail "PowerDNS has no ready pods" return fi # Check PowerDNS service local svc_ip svc_ip=$(kubectl -n dns get svc powerdns -o jsonpath='{.spec.clusterIP}' 2>/dev/null || echo "") if [ -n "$svc_ip" ]; then log_pass "PowerDNS service exists (ClusterIP: $svc_ip)" else log_fail "PowerDNS service does not exist" fi # Check external NLB local nlb_hostname nlb_hostname=$(kubectl -n dns get svc powerdns-external -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "") if [ -n "$nlb_hostname" ]; then log_pass "PowerDNS NLB provisioned: $nlb_hostname" else log_warn "PowerDNS NLB not yet provisioned" fi } check_dns_resolution() { log_info "Checking DNS resolution..." # Get NLB hostname local nlb_hostname nlb_hostname=$(kubectl -n dns get svc powerdns-external -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "") if [ -z "$nlb_hostname" ]; then log_warn "Cannot test DNS resolution - NLB not provisioned" return fi # Get NLB IP local nlb_ip nlb_ip=$(dig +short "$nlb_hostname" | head -1 || echo "") if [ -z "$nlb_ip" ]; then log_warn "Cannot resolve NLB hostname to IP" return fi # Test DNS resolution against PowerDNS local dns_response dns_response=$(dig @"$nlb_ip" "$DOMAIN" +short 2>/dev/null || echo "") if [ -n "$dns_response" ]; then log_pass "DNS resolution working: $DOMAIN -> $dns_response" else log_warn "DNS resolution failed for $DOMAIN (may need NS delegation)" fi } check_dnssec() { log_info "Checking DNSSEC..." # Check DNSSEC via public DNS local dnssec_response dnssec_response=$(dig +dnssec "$DOMAIN" 2>/dev/null | grep -c "ad" || echo "0") if [ "$dnssec_response" -gt 0 ]; then log_pass "DNSSEC is enabled and validated" else log_warn "DNSSEC not validated (may need DS record at registrar)" fi # Check for DNSKEY records local dnskey_count dnskey_count=$(dig DNSKEY "$DOMAIN" +short 2>/dev/null | wc -l | tr -d ' ') if [ "$dnskey_count" -gt 0 ]; then log_pass "DNSKEY records present ($dnskey_count keys)" else log_warn "No DNSKEY records found" fi } check_stalwart() { log_info "Checking Stalwart Mail Server..." # Check if namespace exists if ! kubectl get namespace email &> /dev/null; then log_fail "email namespace does not exist" return fi # Check pod health local ready_pods ready_pods=$(kubectl -n email get pods -l app=stalwart -o json | jq '[.items[] | select(.status.phase == "Running") | select(.status.containerStatuses[]?.ready == true)] | length') if [ "$ready_pods" -ge 1 ]; then log_pass "Stalwart has $ready_pods ready pods" else log_fail "Stalwart has no ready pods" return fi # Check Stalwart services local services=("smtp" "submission" "imap") for svc in "${services[@]}"; do local svc_exists svc_exists=$(kubectl -n email get svc stalwart-"$svc" -o name 2>/dev/null || echo "") if [ -n "$svc_exists" ]; then log_pass "Stalwart $svc service exists" else log_warn "Stalwart $svc service not found" fi done } check_email_tls() { log_info "Checking email TLS..." # Get mail server hostname local mail_host="mail.$DOMAIN" # Check SMTP TLS (port 465) if command -v openssl &> /dev/null; then local smtp_tls smtp_tls=$(echo | timeout 5 openssl s_client -connect "$mail_host":465 2>/dev/null | grep -c "Verify return code: 0" || echo "0") if [ "$smtp_tls" -gt 0 ]; then log_pass "SMTP TLS working on port 465" else log_warn "SMTP TLS check failed (may need DNS propagation)" fi # Check IMAP TLS (port 993) local imap_tls imap_tls=$(echo | timeout 5 openssl s_client -connect "$mail_host":993 2>/dev/null | grep -c "Verify return code: 0" || echo "0") if [ "$imap_tls" -gt 0 ]; then log_pass "IMAP TLS working on port 993" else log_warn "IMAP TLS check failed (may need DNS propagation)" fi else log_warn "openssl not available - skipping TLS checks" fi } check_email_dns_records() { log_info "Checking email DNS records..." # Check MX record local mx_record mx_record=$(dig MX "$DOMAIN" +short 2>/dev/null | head -1 || echo "") if [ -n "$mx_record" ]; then log_pass "MX record exists: $mx_record" else log_warn "No MX record found for $DOMAIN" fi # Check SPF record local spf_record spf_record=$(dig TXT "$DOMAIN" +short 2>/dev/null | grep "v=spf1" || echo "") if [ -n "$spf_record" ]; then log_pass "SPF record exists" else log_warn "No SPF record found" fi # Check DMARC record local dmarc_record dmarc_record=$(dig TXT "_dmarc.$DOMAIN" +short 2>/dev/null | grep "v=DMARC1" || echo "") if [ -n "$dmarc_record" ]; then log_pass "DMARC record exists" else log_warn "No DMARC record found" fi # Check DKIM record local dkim_record dkim_record=$(dig TXT "default._domainkey.$DOMAIN" +short 2>/dev/null | grep "v=DKIM1" || echo "") if [ -n "$dkim_record" ]; then log_pass "DKIM record exists" else log_warn "No DKIM record found (check selector name)" fi } print_summary() { echo "" echo "========================================" echo "Phase 3 Validation Summary" echo "========================================" echo -e " ${GREEN}Passed:${NC} $PASSED" echo -e " ${RED}Failed:${NC} $FAILED" echo -e " ${YELLOW}Warnings:${NC} $WARNINGS" echo "========================================" if [ "$FAILED" -gt 0 ]; then echo "" echo -e "${RED}Phase 3 validation FAILED${NC}" echo "Please fix the issues above before proceeding to Phase 4." exit 1 elif [ "$WARNINGS" -gt 0 ]; then echo "" echo -e "${YELLOW}Phase 3 validation passed with warnings${NC}" echo "DNS propagation may take up to 48 hours." echo "Review warnings above. You may proceed to Phase 4." exit 0 else echo "" echo -e "${GREEN}Phase 3 validation PASSED${NC}" echo "You may proceed to Phase 4." exit 0 fi } main() { echo "========================================" echo "Phase 3 Validation: DNS and Email" echo "========================================" echo "" check_powerdns check_dns_resolution check_dnssec check_stalwart check_email_tls check_email_dns_records print_summary } main "$@"