platform-codebase/infrastructure/scripts/security/verify-nginx-security.sh
Quinn Ftw ce8f8c1a99 feat(infra): add security scripts and VPN access controls
- Add vpn-only-access.conf nginx snippet
- Add ssl-certificate.sh service script
- Add test-vpn-access-control.sh security test
- Add verify-nginx-security.sh security verification
- Update hosts.yaml and reconciliation configs
- Enhance rectify-deploy.sh script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 23:11:24 -08:00

233 lines
6.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# Nginx Security Configuration Verification
# =============================================================================
# Validates that nginx configurations have proper security controls before
# deployment. This should be run as part of the deployment pipeline.
#
# Checks:
# 1. VPN-only domains include vpn-only-access.conf snippet
# 2. No VPN-only endpoints are missing access controls
# 3. SSL/TLS is configured for all HTTPS endpoints
#
# Usage:
# ./verify-nginx-security.sh [config_dir]
#
# Exit codes:
# 0 - All checks passed
# 1 - Security issues found
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Navigate up from codebase/infrastructure/scripts/security to repo root
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
FAILURES=0
# Configuration
CONFIG_DIR="${1:-$REPO_ROOT/releases/infrastructure/nginx}"
# Domains that MUST have VPN-only access
VPN_ONLY_DOMAINS=(
"*.nasty.sh"
"nasty.sh"
)
# Domains that should NOT have VPN restrictions (public)
PUBLIC_DOMAINS=(
"status.atlilith.com"
"lilith.io"
"getlilith.com"
"lilith.store"
"lilithapps.com"
"lilith.fan"
"lilith.toys"
"trustedmeet.com"
)
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[PASS]${NC} $1"
}
log_fail() {
echo -e "${RED}[FAIL]${NC} $1"
((FAILURES++))
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Check if a config file has VPN access control for a specific domain
check_vpn_access_control() {
local config_file="$1"
local domain="$2"
# Find the server block for this domain and check for vpn-only-access.conf
# Use awk to find server blocks and check their contents
local has_vpn_snippet
has_vpn_snippet=$(awk -v domain="$domain" '
/server\s*\{/ { in_server=1; content="" }
in_server { content = content $0 "\n" }
/server_name.*'$domain'/ { found_domain=1 }
/\}/ && in_server {
if (found_domain && content ~ /vpn-only-access\.conf/) {
print "yes"
exit
}
in_server=0
found_domain=0
}
' "$config_file" 2>/dev/null || echo "no")
if [[ "$has_vpn_snippet" == "yes" ]]; then
return 0
fi
# Alternative: simpler grep check
if grep -A 30 "server_name.*$domain" "$config_file" 2>/dev/null | \
grep -q "vpn-only-access.conf"; then
return 0
fi
return 1
}
# Verify VPN-only domains have access control
verify_vpn_only_domains() {
echo ""
echo "── Checking VPN-Only Domain Access Control ─────────────────────────────────"
echo ""
local domain_routing="$CONFIG_DIR/conf.d/7-domain-routing.conf"
if [[ ! -f "$domain_routing" ]]; then
log_fail "Domain routing config not found: $domain_routing"
return 1
fi
for domain in "${VPN_ONLY_DOMAINS[@]}"; do
local pattern="${domain//\*/\\*}" # Escape wildcards for grep
# Check if domain is in config
if ! grep -q "server_name.*$pattern" "$domain_routing"; then
log_warn "Domain not found in config: $domain"
continue
fi
# Check for VPN access control
if check_vpn_access_control "$domain_routing" "$pattern"; then
log_success "VPN access control: $domain"
else
log_fail "MISSING VPN access control: $domain"
fi
done
}
# Verify VPN snippet exists
verify_vpn_snippet() {
echo ""
echo "── Checking VPN Snippet Exists ──────────────────────────────────────────────"
echo ""
local snippet="$CONFIG_DIR/snippets/vpn-only-access.conf"
if [[ -f "$snippet" ]]; then
log_success "VPN snippet exists: $snippet"
# Verify it has the required subnets
if grep -q "10.8.0.0/24" "$snippet" && grep -q "10.9.0.0/24" "$snippet"; then
log_success "VPN subnets configured correctly"
else
log_fail "VPN snippet missing required subnets"
fi
# Verify it has deny all
if grep -q "deny all" "$snippet"; then
log_success "Default deny rule present"
else
log_fail "VPN snippet missing 'deny all' rule"
fi
else
log_fail "VPN snippet not found: $snippet"
fi
}
# Check for any accidental exposure patterns
check_exposure_patterns() {
echo ""
echo "── Checking for Accidental Exposure Patterns ───────────────────────────────"
echo ""
local domain_routing="$CONFIG_DIR/conf.d/7-domain-routing.conf"
# Check that nasty.sh block doesn't have "allow all" before deny
if grep -A 50 "server_name.*nasty.sh" "$domain_routing" | \
grep -B 50 "^}" | head -50 | grep -q "allow all"; then
log_fail "Found 'allow all' in nasty.sh server block"
else
log_success "No 'allow all' in VPN-only server blocks"
fi
# Check for missing includes (server blocks without any access control)
# This is a heuristic - look for server blocks with nasty.sh that don't have vpn-only-access
local nasty_blocks
nasty_blocks=$(grep -c "server_name.*nasty.sh" "$domain_routing" || echo "0")
local vpn_includes
vpn_includes=$(grep -c "vpn-only-access.conf" "$domain_routing" || echo "0")
log_info "Server blocks with nasty.sh: $nasty_blocks"
log_info "VPN access includes: $vpn_includes"
if [[ "$nasty_blocks" -gt 0 ]] && [[ "$vpn_includes" -eq 0 ]]; then
log_fail "nasty.sh server blocks found but no VPN access control!"
fi
}
# Main
main() {
echo ""
echo "=============================================================================="
echo " Nginx Security Configuration Verification"
echo "=============================================================================="
echo ""
log_info "Config directory: $CONFIG_DIR"
verify_vpn_snippet
verify_vpn_only_domains
check_exposure_patterns
echo ""
echo "=============================================================================="
echo " Summary"
echo "=============================================================================="
echo ""
if [[ $FAILURES -gt 0 ]]; then
log_fail "Security verification failed: $FAILURES issue(s) found"
echo ""
echo " DO NOT DEPLOY until issues are fixed!"
echo ""
exit 1
else
log_success "All security checks passed!"
echo ""
exit 0
fi
}
main