#!/bin/bash set -euo pipefail # Cloudflare Tunnel Configuration Script # Load environment variables from .env if it exists SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "${SCRIPT_DIR}/../.env" ]; then set -a source <(grep -v '^#' "${SCRIPT_DIR}/../.env" | grep -v '^$' | sed 's/^/export /') set +a fi CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}" CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}" CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}" ZONE_ID="${CLOUDFLARE_ZONE_ID:-${ZONE_ID:-}}" ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-${ACCOUNT_ID:-}}" log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2 } error() { log "ERROR: $*" exit 1 } check_prerequisites() { # Check authentication method if [ -z "${CLOUDFLARE_API_TOKEN}" ] && [ -z "${CLOUDFLARE_API_KEY}" ]; then error "Either CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY must be set" fi if [ -z "${CLOUDFLARE_API_TOKEN}" ] && [ -z "${CLOUDFLARE_EMAIL}" ]; then error "If using CLOUDFLARE_API_KEY, CLOUDFLARE_EMAIL must also be set" fi if [ -z "${ACCOUNT_ID}" ]; then warn "ACCOUNT_ID not set, attempting to get from API..." get_account_id fi if ! command -v cloudflared &> /dev/null; then error "cloudflared is not installed. Install it first." fi } get_account_id() { if [ -n "${CLOUDFLARE_API_TOKEN}" ]; then ACCOUNT_ID=$(curl -s -X GET \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/accounts" | \ jq -r '.result[0].id') elif [ -n "${CLOUDFLARE_API_KEY}" ] && [ -n "${CLOUDFLARE_EMAIL}" ]; then ACCOUNT_ID=$(curl -s -X GET \ -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \ -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/accounts" | \ jq -r '.result[0].id') fi if [ -n "${ACCOUNT_ID}" ] && [ "${ACCOUNT_ID}" != "null" ]; then log "Account ID: ${ACCOUNT_ID}" export CLOUDFLARE_ACCOUNT_ID="${ACCOUNT_ID}" else error "Failed to get Account ID" fi } create_tunnel() { local tunnel_name=$1 log "Creating Cloudflare tunnel: ${tunnel_name}" # Create tunnel via API local auth_header if [ -n "${CLOUDFLARE_API_TOKEN}" ]; then TUNNEL_ID=$(curl -s -X POST \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel" \ -d "{\"name\":\"${tunnel_name}\",\"config_src\":\"local\"}" \ | jq -r '.result.id') else TUNNEL_ID=$(curl -s -X POST \ -H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \ -H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel" \ -d "{\"name\":\"${tunnel_name}\",\"config_src\":\"local\"}" \ | jq -r '.result.id') fi if [ -z "${TUNNEL_ID}" ] || [ "${TUNNEL_ID}" = "null" ]; then error "Failed to create tunnel ${tunnel_name}" fi log "Tunnel created with ID: ${TUNNEL_ID}" echo "${TUNNEL_ID}" } get_tunnel_token() { local tunnel_id=$1 log "Getting tunnel token for ${tunnel_id}..." TOKEN=$(curl -s -X GET \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/cfd_tunnel/${tunnel_id}/token" \ | jq -r '.result.token') if [ -z "${TOKEN}" ] || [ "${TOKEN}" = "null" ]; then error "Failed to get tunnel token" fi echo "${TOKEN}" } configure_dns() { local hostname=$1 local tunnel_id=$2 log "Configuring DNS for ${hostname}..." # Create CNAME record curl -s -X POST \ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ -H "Content-Type: application/json" \ "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \ -d "{ \"type\": \"CNAME\", \"name\": \"${hostname}\", \"content\": \"${tunnel_id}.cfargotunnel.com\", \"ttl\": 1, \"proxied\": true }" > /dev/null log "DNS record created for ${hostname}" } setup_control_plane_tunnel() { log "Setting up control plane tunnel..." TUNNEL_ID=$(create_tunnel "control-plane-tunnel") TUNNEL_TOKEN=$(get_tunnel_token "${TUNNEL_ID}") log "Control plane tunnel token: ${TUNNEL_TOKEN}" log "Save this token securely and use it when running cloudflared on control plane nodes" # Configure DNS for control plane services configure_dns "portal" "${TUNNEL_ID}" configure_dns "rancher" "${TUNNEL_ID}" configure_dns "argocd" "${TUNNEL_ID}" configure_dns "grafana" "${TUNNEL_ID}" configure_dns "vault" "${TUNNEL_ID}" configure_dns "keycloak" "${TUNNEL_ID}" } setup_proxmox_tunnels() { local sites=("site-1" "site-2" "site-3") for site in "${sites[@]}"; do log "Setting up tunnel for ${site}..." TUNNEL_ID=$(create_tunnel "proxmox-${site}-tunnel") TUNNEL_TOKEN=$(get_tunnel_token "${TUNNEL_ID}") log "${site} tunnel token: ${TUNNEL_TOKEN}" log "Save this token and use it when running setup-proxmox-agents.sh on ${site} nodes" done } main() { log "Starting Cloudflare tunnel configuration..." check_prerequisites setup_control_plane_tunnel setup_proxmox_tunnels log "" log "Cloudflare tunnel configuration completed!" log "" log "Next steps:" log "1. Save all tunnel tokens securely" log "2. Use tokens when running cloudflared on respective nodes" log "3. Verify DNS records are created correctly" log "4. Test tunnel connectivity" } main "$@"