hearth/scripts/deploy-phase3-dns-email.sh
Eric Garcia e78000831e Initial commit: Port infrastructure from coherence-mcp
Hearth is the infrastructure home for the letemcook ecosystem.

Ported from coherence-mcp/infra:
- Terraform modules (VPC, EKS, IAM, NLB, S3, storage)
- Kubernetes manifests (Forgejo, ingress, cert-manager, karpenter)
- Deployment scripts (phased rollout)

Status: Not deployed. EKS cluster needs to be provisioned.

Next steps:
1. Bootstrap terraform backend
2. Deploy phase 1 (foundation)
3. Deploy phase 2 (core services including Forgejo)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 06:06:13 -05:00

282 lines
7.8 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Phase 3: DNS and Email Deployment (RFC 0041)
#
# This script deploys DNS and email services including:
# - PowerDNS for authoritative DNS
# - Stalwart Mail Server for email
# - Vault S/MIME PKI configuration
#
# Usage:
# ./deploy-phase3-dns-email.sh [--dry-run] [--skip-powerdns] [--skip-stalwart] [--skip-vault-pki]
#
# Prerequisites:
# - Phase 2 (Core Services) must be deployed and validated
# - kubectl configured for EKS cluster
# - DNS registrar access for NS record delegation
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INFRA_DIR="$(dirname "$SCRIPT_DIR")"
TERRAFORM_DIR="$INFRA_DIR/terraform"
K8S_DIR="$INFRA_DIR/kubernetes"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Flags
DRY_RUN=false
SKIP_POWERDNS=false
SKIP_STALWART=false
SKIP_VAULT_PKI=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
shift
;;
--skip-powerdns)
SKIP_POWERDNS=true
shift
;;
--skip-stalwart)
SKIP_STALWART=true
shift
;;
--skip-vault-pki)
SKIP_VAULT_PKI=true
shift
;;
-h|--help)
echo "Usage: $0 [--dry-run] [--skip-powerdns] [--skip-stalwart] [--skip-vault-pki]"
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
exit 1
;;
esac
done
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
run_cmd() {
if [ "$DRY_RUN" = true ]; then
echo -e "${YELLOW}[DRY-RUN]${NC} Would run: $*"
else
"$@"
fi
}
check_prerequisites() {
log_info "Checking prerequisites..."
# Check kubectl connectivity
if ! kubectl cluster-info &> /dev/null; then
log_error "kubectl not connected to cluster."
exit 1
fi
# Check Vault is running and unsealed
if [ "$DRY_RUN" = false ]; then
local vault_status
vault_status=$(kubectl -n vault exec vault-0 -- vault status -format=json 2>/dev/null || echo '{}')
local sealed
sealed=$(echo "$vault_status" | jq -r '.sealed // true')
if [ "$sealed" = "true" ]; then
log_error "Vault is sealed. Ensure Phase 2 is complete."
exit 1
fi
fi
# Check Keycloak is running
if ! kubectl -n keycloak get pods -l app=keycloak -o jsonpath='{.items[0].status.phase}' 2>/dev/null | grep -q Running; then
log_error "Keycloak not running. Ensure Phase 2 is complete."
exit 1
fi
log_success "All prerequisites met"
}
deploy_powerdns() {
if [ "$SKIP_POWERDNS" = true ]; then
log_warn "Skipping PowerDNS deployment"
return
fi
log_info "Deploying PowerDNS..."
# Deploy PowerDNS
run_cmd kubectl apply -k "$K8S_DIR/powerdns/"
# Wait for PowerDNS pods
if [ "$DRY_RUN" = false ]; then
log_info "Waiting for PowerDNS pods to be ready..."
kubectl -n dns wait --for=condition=ready pod -l app=powerdns --timeout=300s
fi
# Initialize DNS records
if [ -f "$K8S_DIR/powerdns/dns-records-job.yaml" ]; then
log_info "Initializing DNS records..."
run_cmd kubectl apply -f "$K8S_DIR/powerdns/dns-records-job.yaml"
if [ "$DRY_RUN" = false ]; then
kubectl -n dns wait --for=condition=complete job/dns-records-init --timeout=120s || true
fi
fi
# Enable DNSSEC
if [ -f "$K8S_DIR/powerdns/dnssec-setup-job.yaml" ]; then
log_info "Enabling DNSSEC..."
run_cmd kubectl apply -f "$K8S_DIR/powerdns/dnssec-setup-job.yaml"
if [ "$DRY_RUN" = false ]; then
kubectl -n dns wait --for=condition=complete job/dnssec-setup --timeout=120s || true
fi
fi
log_success "PowerDNS deployment complete"
# Display NS record information
echo ""
log_info "Important: Update your DNS registrar with the following NS records:"
if [ "$DRY_RUN" = false ]; then
local nlb_dns
nlb_dns=$(kubectl -n dns get svc powerdns-external -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "<pending>")
echo " NS record should point to: $nlb_dns"
fi
echo ""
}
deploy_stalwart() {
if [ "$SKIP_STALWART" = true ]; then
log_warn "Skipping Stalwart deployment"
return
fi
log_info "Deploying Stalwart Mail Server..."
# Deploy Stalwart
run_cmd kubectl apply -k "$K8S_DIR/stalwart/"
# Wait for Stalwart pods
if [ "$DRY_RUN" = false ]; then
log_info "Waiting for Stalwart pods to be ready..."
kubectl -n email wait --for=condition=ready pod -l app=stalwart --timeout=300s
fi
# Generate DKIM keys
if [ -f "$K8S_DIR/stalwart/dkim-setup-job.yaml" ]; then
log_info "Generating DKIM keys..."
run_cmd kubectl apply -f "$K8S_DIR/stalwart/dkim-setup-job.yaml"
if [ "$DRY_RUN" = false ]; then
kubectl -n email wait --for=condition=complete job/dkim-setup --timeout=120s || true
# Display DKIM record
echo ""
log_info "DKIM TXT record to add to DNS:"
kubectl -n email logs job/dkim-setup 2>/dev/null | grep -A5 "DKIM TXT record" || echo " Check job logs for DKIM record"
fi
fi
log_success "Stalwart deployment complete"
# Display email DNS records
echo ""
log_info "Ensure the following DNS records are configured:"
echo " SPF: v=spf1 mx a ~all"
echo " DMARC: v=DMARC1; p=quarantine; rua=mailto:dmarc@coherence.dev"
echo ""
}
deploy_vault_smime_pki() {
if [ "$SKIP_VAULT_PKI" = true ]; then
log_warn "Skipping Vault S/MIME PKI deployment"
return
fi
log_info "Deploying Vault S/MIME PKI..."
cd "$TERRAFORM_DIR"
if [ "$DRY_RUN" = true ]; then
run_cmd terraform plan -target=module.vault_smime_pki
else
terraform plan -target=module.vault_smime_pki -out=pki.tfplan
terraform apply pki.tfplan
rm -f pki.tfplan
fi
log_success "Vault S/MIME PKI deployment complete"
}
validate_phase3() {
log_info "Running Phase 3 validation..."
local validation_script="$SCRIPT_DIR/validate-phase3.sh"
if [ -x "$validation_script" ]; then
if [ "$DRY_RUN" = true ]; then
log_info "Would run validation script: $validation_script"
else
"$validation_script"
fi
else
log_warn "Validation script not found or not executable: $validation_script"
fi
}
main() {
echo "========================================"
echo "Phase 3: DNS and Email"
echo "RFC 0041 Deployment"
echo "========================================"
echo ""
if [ "$DRY_RUN" = true ]; then
log_warn "Running in DRY-RUN mode - no changes will be made"
echo ""
fi
check_prerequisites
deploy_powerdns
deploy_stalwart
deploy_vault_smime_pki
validate_phase3
echo ""
echo "========================================"
log_success "Phase 3 deployment complete!"
echo "========================================"
echo ""
echo "IMPORTANT MANUAL STEPS:"
echo " 1. Update DNS registrar with NS records pointing to PowerDNS NLB"
echo " 2. Add DKIM TXT record to DNS"
echo " 3. Add SPF and DMARC records"
echo " 4. Wait for DNS propagation (may take up to 48 hours)"
echo ""
echo "Next steps:"
echo " 1. Run validate-phase3.sh to verify deployment"
echo " 2. Tag this deployment: git tag -a v0.3.0-phase3 -m 'Phase 3: DNS and Email'"
echo " 3. Proceed to Phase 4: ./deploy-phase4-observability.sh"
}
main "$@"