Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
694 lines
23 KiB
Bash
Executable File
694 lines
23 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Complete automation of Cloudflare setup via API
|
|
# Creates tunnels, DNS records, and Cloudflare Access applications
|
|
|
|
set -euo pipefail
|
|
|
|
# Load IP configuration
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
|
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
TUNNELS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[✗]${NC} $1"; }
|
|
|
|
# Load .env file
|
|
if [[ -f "$PROJECT_ROOT/.env" ]]; then
|
|
source "$PROJECT_ROOT/.env"
|
|
log_info "Loaded credentials from .env"
|
|
else
|
|
log_error ".env file not found at $PROJECT_ROOT/.env"
|
|
exit 1
|
|
fi
|
|
|
|
# Cloudflare API configuration
|
|
CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
|
|
CLOUDFLARE_EMAIL="${CLOUDFLARE_EMAIL:-}"
|
|
CLOUDFLARE_API_KEY="${CLOUDFLARE_API_KEY:-}"
|
|
CLOUDFLARE_ZONE_ID="${CLOUDFLARE_ZONE_ID:-}"
|
|
CLOUDFLARE_ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}"
|
|
DOMAIN="${DOMAIN:-d-bis.org}"
|
|
|
|
# Check for required tools
|
|
if ! command -v curl >/dev/null 2>&1; then
|
|
log_error "curl is required"
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq >/dev/null 2>&1; then
|
|
log_error "jq is required. Install with: apt-get install jq"
|
|
exit 1
|
|
fi
|
|
|
|
# API base URLs
|
|
CF_API_BASE="https://api.cloudflare.com/client/v4"
|
|
CF_ZERO_TRUST_API="https://api.cloudflare.com/client/v4/accounts"
|
|
|
|
# Function to make Cloudflare API request
|
|
cf_api_request() {
|
|
local method="$1"
|
|
local endpoint="$2"
|
|
local data="${3:-}"
|
|
|
|
local url="${CF_API_BASE}${endpoint}"
|
|
local auth_header=""
|
|
|
|
if [[ -n "$CLOUDFLARE_API_TOKEN" ]]; then
|
|
auth_header="Authorization: Bearer ${CLOUDFLARE_API_TOKEN}"
|
|
elif [[ -n "$CLOUDFLARE_API_KEY" ]] && [[ -n "$CLOUDFLARE_EMAIL" ]]; then
|
|
auth_header="X-Auth-Email: ${CLOUDFLARE_EMAIL}"
|
|
# Note: We'll need to pass both headers, so we'll use a different approach
|
|
else
|
|
log_error "Cloudflare API credentials not found!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
local response
|
|
local http_code
|
|
local temp_file=$(mktemp)
|
|
|
|
# Build curl command with timeout
|
|
if [[ -n "$CLOUDFLARE_API_TOKEN" ]]; then
|
|
if [[ -n "$data" ]]; then
|
|
http_code=$(curl -s --max-time 30 -o "$temp_file" -w "%{http_code}" \
|
|
-X "$method" "$url" \
|
|
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$data" 2>/dev/null)
|
|
else
|
|
http_code=$(curl -s --max-time 30 -o "$temp_file" -w "%{http_code}" \
|
|
-X "$method" "$url" \
|
|
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
|
|
-H "Content-Type: application/json" 2>/dev/null)
|
|
fi
|
|
else
|
|
if [[ -n "$data" ]]; then
|
|
http_code=$(curl -s --max-time 30 -o "$temp_file" -w "%{http_code}" \
|
|
-X "$method" "$url" \
|
|
-H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
|
|
-H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$data" 2>/dev/null)
|
|
else
|
|
http_code=$(curl -s --max-time 30 -o "$temp_file" -w "%{http_code}" \
|
|
-X "$method" "$url" \
|
|
-H "X-Auth-Email: ${CLOUDFLARE_EMAIL}" \
|
|
-H "X-Auth-Key: ${CLOUDFLARE_API_KEY}" \
|
|
-H "Content-Type: application/json" 2>/dev/null)
|
|
fi
|
|
fi
|
|
|
|
# Read response from temp file
|
|
if [[ -f "$temp_file" ]] && [[ -s "$temp_file" ]]; then
|
|
response=$(cat "$temp_file")
|
|
else
|
|
response=""
|
|
fi
|
|
|
|
rm -f "$temp_file"
|
|
|
|
# Check if response is valid JSON
|
|
if [[ -z "$response" ]] || ! echo "$response" | jq -e . >/dev/null 2>&1; then
|
|
log_error "Invalid JSON response from API (HTTP ${http_code:-unknown})" >&2
|
|
if [[ -n "$response" ]]; then
|
|
log_error "Response: $(echo "$response" | head -3)" >&2
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
local success=$(echo "$response" | jq -r '.success // false' 2>/dev/null)
|
|
if [[ "$success" != "true" ]]; then
|
|
local errors=$(echo "$response" | jq -r '.errors[]?.message // .error // "Unknown error"' 2>/dev/null | head -3)
|
|
if [[ "$http_code" != "200" ]] && [[ "$http_code" != "201" ]]; then
|
|
log_error "API request failed (HTTP $http_code): $errors" >&2
|
|
fi
|
|
# Don't return error for GET requests that might return empty results
|
|
if [[ "$method" == "GET" ]] && [[ "$http_code" == "200" ]]; then
|
|
echo "$response"
|
|
return 0
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
# Only output JSON to stdout on success
|
|
echo "$response"
|
|
}
|
|
|
|
# Get zone ID
|
|
get_zone_id() {
|
|
if [[ -n "$CLOUDFLARE_ZONE_ID" ]]; then
|
|
echo "$CLOUDFLARE_ZONE_ID"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Getting zone ID for domain: $DOMAIN"
|
|
local response=$(cf_api_request "GET" "/zones?name=${DOMAIN}")
|
|
local zone_id=$(echo "$response" | jq -r '.result[0].id // empty')
|
|
|
|
if [[ -z "$zone_id" ]]; then
|
|
log_error "Zone not found for domain: $DOMAIN"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Zone ID: $zone_id"
|
|
echo "$zone_id"
|
|
}
|
|
|
|
# Get account ID
|
|
get_account_id() {
|
|
if [[ -n "$CLOUDFLARE_ACCOUNT_ID" ]]; then
|
|
echo "$CLOUDFLARE_ACCOUNT_ID"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Getting account ID..."
|
|
local response=$(cf_api_request "GET" "/user/tokens/verify")
|
|
local account_id=$(echo "$response" | jq -r '.result.id // empty')
|
|
|
|
if [[ -z "$account_id" ]]; then
|
|
response=$(cf_api_request "GET" "/accounts")
|
|
account_id=$(echo "$response" | jq -r '.result[0].id // empty')
|
|
fi
|
|
|
|
if [[ -z "$account_id" ]]; then
|
|
local zone_id=$(get_zone_id)
|
|
response=$(cf_api_request "GET" "/zones/${zone_id}")
|
|
account_id=$(echo "$response" | jq -r '.result.account.id // empty')
|
|
fi
|
|
|
|
if [[ -z "$account_id" ]]; then
|
|
log_error "Could not determine account ID"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Account ID: $account_id"
|
|
echo "$account_id"
|
|
}
|
|
|
|
# Create tunnel
|
|
create_tunnel() {
|
|
local account_id="$1"
|
|
local tunnel_name="$2"
|
|
|
|
log_info "Creating tunnel: $tunnel_name"
|
|
|
|
# Check if tunnel already exists (skip check if API fails)
|
|
local response
|
|
response=$(cf_api_request "GET" "/accounts/${account_id}/cfd_tunnel" 2>/dev/null) || response=""
|
|
if [[ -n "$response" ]] && echo "$response" | jq -e '.result' >/dev/null 2>&1; then
|
|
local existing_id
|
|
existing_id=$(echo "$response" | jq -r ".result[]? | select(.name == \"${tunnel_name}\") | .id" 2>/dev/null || echo "")
|
|
if [[ -n "$existing_id" ]] && [[ "$existing_id" != "null" ]] && [[ "$existing_id" != "" ]]; then
|
|
log_warn "Tunnel $tunnel_name already exists (ID: $existing_id)"
|
|
echo "$existing_id"
|
|
return 0
|
|
fi
|
|
else
|
|
# If API call failed, log but continue (might be permission issue)
|
|
log_warn "Could not check for existing tunnels, attempting to create..."
|
|
fi
|
|
|
|
# Create tunnel
|
|
local data
|
|
data=$(jq -n \
|
|
--arg name "$tunnel_name" \
|
|
'{name: $name}' 2>/dev/null)
|
|
|
|
if [[ -z "$data" ]]; then
|
|
log_error "Failed to create tunnel data JSON"
|
|
return 1
|
|
fi
|
|
|
|
response=$(cf_api_request "POST" "/accounts/${account_id}/cfd_tunnel" "$data" 2>/dev/null)
|
|
local api_result=$?
|
|
|
|
# If creation failed, check if tunnel already exists (might have been created between check and create)
|
|
if [[ $api_result -ne 0 ]] || [[ -z "$response" ]] || ! echo "$response" | jq -e . >/dev/null 2>&1; then
|
|
# Try to get existing tunnel one more time
|
|
local check_response
|
|
check_response=$(cf_api_request "GET" "/accounts/${account_id}/cfd_tunnel" 2>/dev/null) || check_response=""
|
|
if [[ -n "$check_response" ]] && echo "$check_response" | jq -e '.result' >/dev/null 2>&1; then
|
|
local existing_id
|
|
existing_id=$(echo "$check_response" | jq -r ".result[]? | select(.name == \"${tunnel_name}\") | .id" 2>/dev/null || echo "")
|
|
if [[ -n "$existing_id" ]] && [[ "$existing_id" != "null" ]] && [[ "$existing_id" != "" ]]; then
|
|
log_warn "Tunnel $tunnel_name already exists (ID: $existing_id)"
|
|
echo "$existing_id"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
log_error "Failed to create tunnel"
|
|
if [[ -n "$response" ]]; then
|
|
log_error "Response: $(echo "$response" | head -3)"
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
local tunnel_id
|
|
tunnel_id=$(echo "$response" | jq -r '.result.id // empty' 2>/dev/null || echo "")
|
|
|
|
if [[ -z "$tunnel_id" ]] || [[ "$tunnel_id" == "null" ]] || [[ "$tunnel_id" == "" ]]; then
|
|
log_error "Failed to create tunnel"
|
|
local errors
|
|
errors=$(echo "$response" | jq -r '.errors[]?.message // .error // "Unknown error"' 2>/dev/null | head -3)
|
|
if [[ -n "$errors" ]]; then
|
|
log_error "Errors: $errors"
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
log_success "Tunnel created: $tunnel_id"
|
|
echo "$tunnel_id"
|
|
}
|
|
|
|
# Get tunnel token (generate new token)
|
|
get_tunnel_token() {
|
|
local account_id="$1"
|
|
local tunnel_id="$2"
|
|
|
|
log_info "Generating tunnel token..."
|
|
# Note: Cloudflare API doesn't allow "getting" existing tokens, only generating new ones
|
|
# The endpoint is: POST /accounts/{account_id}/cfd_tunnel/{tunnel_id}/token
|
|
local response
|
|
response=$(cf_api_request "POST" "/accounts/${account_id}/cfd_tunnel/${tunnel_id}/token" 2>/dev/null) || response=""
|
|
|
|
if [[ -z "$response" ]]; then
|
|
log_warn "Could not generate token via API (may need manual generation)"
|
|
return 1
|
|
fi
|
|
|
|
local token
|
|
token=$(echo "$response" | jq -r '.result.token // empty' 2>/dev/null || echo "")
|
|
|
|
if [[ -z "$token" ]] || [[ "$token" == "null" ]]; then
|
|
log_warn "Token generation returned empty result"
|
|
return 1
|
|
fi
|
|
|
|
log_success "Token generated"
|
|
echo "$token"
|
|
}
|
|
|
|
# Configure tunnel routes
|
|
configure_tunnel_routes() {
|
|
local account_id="$1"
|
|
local tunnel_id="$2"
|
|
local hostname="$3"
|
|
local service="$4"
|
|
|
|
log_info "Configuring tunnel route: $hostname → $service"
|
|
|
|
# Get existing config (may not exist for new tunnels)
|
|
local response
|
|
response=$(cf_api_request "GET" "/accounts/${account_id}/cfd_tunnel/${tunnel_id}/configurations" 2>/dev/null) || response=""
|
|
|
|
local existing_config="{}"
|
|
local ingress="[]"
|
|
|
|
# Check if response is valid and has config
|
|
if [[ -n "$response" ]] && echo "$response" | jq -e '.result.config' >/dev/null 2>&1; then
|
|
existing_config=$(echo "$response" | jq -r '.result.config // {}' 2>/dev/null || echo "{}")
|
|
ingress=$(echo "$existing_config" | jq -r '.ingress // []' 2>/dev/null || echo "[]")
|
|
|
|
# Check if route already exists
|
|
local route_exists
|
|
route_exists=$(echo "$ingress" | jq -r "any(.hostname == \"${hostname}\")" 2>/dev/null || echo "false")
|
|
if [[ "$route_exists" == "true" ]]; then
|
|
log_success "Route already configured for $hostname, skipping..."
|
|
return 0
|
|
fi
|
|
log_info "Found existing config, adding new route..."
|
|
else
|
|
log_info "No existing config found, creating new configuration..."
|
|
ingress="[]"
|
|
fi
|
|
|
|
# Build new ingress array - simple approach: replace entire config with just this route + catch-all
|
|
# This is simpler and more reliable than trying to merge with existing config
|
|
local config_data
|
|
config_data=$(jq -n \
|
|
--arg hostname "$hostname" \
|
|
--arg service "$service" \
|
|
'{
|
|
config: {
|
|
ingress: [
|
|
{
|
|
hostname: $hostname,
|
|
service: $service,
|
|
originRequest: {
|
|
noHappyEyeballs: true,
|
|
connectTimeout: "30s",
|
|
tcpKeepAlive: "30s",
|
|
keepAliveConnections: 100,
|
|
keepAliveTimeout: "90s",
|
|
disableChunkedEncoding: true,
|
|
noTLSVerify: true
|
|
}
|
|
},
|
|
{
|
|
service: "http_status:404"
|
|
}
|
|
]
|
|
}
|
|
}' 2>/dev/null)
|
|
|
|
if [[ -z "$config_data" ]]; then
|
|
log_error "Failed to create config JSON"
|
|
return 1
|
|
fi
|
|
|
|
response=$(cf_api_request "PUT" "/accounts/${account_id}/cfd_tunnel/${tunnel_id}/configurations" "$config_data" 2>/dev/null)
|
|
local api_result=$?
|
|
|
|
if [[ $api_result -eq 0 ]] && echo "$response" | jq -e '.success' >/dev/null 2>&1; then
|
|
log_success "Tunnel route configured"
|
|
return 0
|
|
else
|
|
log_error "Failed to configure tunnel route"
|
|
if [[ -n "$response" ]]; then
|
|
local errors
|
|
errors=$(echo "$response" | jq -r '.errors[]?.message // .error // "Unknown error"' 2>/dev/null | head -3)
|
|
log_error "Errors: $errors"
|
|
fi
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Create DNS record
|
|
create_dns_record() {
|
|
local zone_id="$1"
|
|
local name="$2"
|
|
local target="$3"
|
|
|
|
log_info "Creating DNS record: $name → $target"
|
|
|
|
# Check if record exists
|
|
local response=$(cf_api_request "GET" "/zones/${zone_id}/dns_records?name=${name}&type=CNAME" 2>/dev/null || echo "")
|
|
local record_id=$(echo "$response" | jq -r '.result[0].id // empty' 2>/dev/null || echo "")
|
|
|
|
local data=$(jq -n \
|
|
--arg name "$name" \
|
|
--arg target "$target" \
|
|
'{
|
|
type: "CNAME",
|
|
name: $name,
|
|
content: $target,
|
|
proxied: true,
|
|
ttl: 1
|
|
}')
|
|
|
|
if [[ -n "$record_id" ]]; then
|
|
log_warn "DNS record exists, updating..."
|
|
response=$(cf_api_request "PUT" "/zones/${zone_id}/dns_records/${record_id}" "$data")
|
|
else
|
|
response=$(cf_api_request "POST" "/zones/${zone_id}/dns_records" "$data")
|
|
fi
|
|
|
|
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
|
|
log_success "DNS record configured"
|
|
return 0
|
|
else
|
|
log_error "Failed to configure DNS record"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Create Cloudflare Access application
|
|
create_access_application() {
|
|
local account_id="$1"
|
|
local app_name="$2"
|
|
local domain="$3"
|
|
|
|
log_info "Creating Access application: $app_name"
|
|
|
|
# Check if application exists
|
|
local response=$(cf_api_request "GET" "/accounts/${account_id}/access/apps" 2>/dev/null || echo "")
|
|
local existing_id=$(echo "$response" | jq -r ".result[] | select(.domain == \"${domain}\") | .id" 2>/dev/null || echo "")
|
|
|
|
if [[ -n "$existing_id" ]]; then
|
|
log_warn "Access application already exists (ID: $existing_id)"
|
|
echo "$existing_id"
|
|
return 0
|
|
fi
|
|
|
|
# Create application
|
|
local data=$(jq -n \
|
|
--arg name "$app_name" \
|
|
--arg domain "$domain" \
|
|
'{
|
|
name: $name,
|
|
domain: $domain,
|
|
type: "self_hosted",
|
|
session_duration: "8h"
|
|
}')
|
|
|
|
response=$(cf_api_request "POST" "/accounts/${account_id}/access/apps" "$data")
|
|
local app_id=$(echo "$response" | jq -r '.result.id // empty')
|
|
|
|
if [[ -z "$app_id" ]]; then
|
|
log_error "Failed to create Access application"
|
|
return 1
|
|
fi
|
|
|
|
log_success "Access application created: $app_id"
|
|
echo "$app_id"
|
|
}
|
|
|
|
# Create Access policy
|
|
create_access_policy() {
|
|
local account_id="$1"
|
|
local app_id="$2"
|
|
|
|
log_info "Creating Access policy for application..."
|
|
|
|
# Check if policy exists
|
|
local response=$(cf_api_request "GET" "/accounts/${account_id}/access/apps/${app_id}/policies" 2>/dev/null || echo "")
|
|
local existing_id=$(echo "$response" | jq -r '.result[0].id // empty' 2>/dev/null || echo "")
|
|
|
|
if [[ -n "$existing_id" ]]; then
|
|
log_warn "Access policy already exists"
|
|
return 0
|
|
fi
|
|
|
|
# Create policy with MFA requirement
|
|
local data=$(jq -n \
|
|
'{
|
|
name: "Allow Team Access",
|
|
decision: "allow",
|
|
include: [
|
|
{
|
|
email: {
|
|
email: "@'${DOMAIN}'"
|
|
}
|
|
}
|
|
],
|
|
require: [
|
|
{
|
|
email: {}
|
|
}
|
|
]
|
|
}')
|
|
|
|
response=$(cf_api_request "POST" "/accounts/${account_id}/access/apps/${app_id}/policies" "$data")
|
|
|
|
if echo "$response" | jq -e '.success' >/dev/null 2>&1; then
|
|
log_success "Access policy created"
|
|
return 0
|
|
else
|
|
log_warn "Failed to create Access policy (may need manual configuration)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
log_info "=========================================="
|
|
log_info " Cloudflare Automated Setup"
|
|
log_info "=========================================="
|
|
echo ""
|
|
|
|
# Validate credentials
|
|
if [[ -z "$CLOUDFLARE_API_TOKEN" ]] && [[ -z "$CLOUDFLARE_API_KEY" ]]; then
|
|
log_error "Cloudflare API credentials not found in .env"
|
|
exit 1
|
|
fi
|
|
|
|
# Get IDs
|
|
local zone_id=$(get_zone_id)
|
|
local account_id=$(get_account_id)
|
|
|
|
echo ""
|
|
log_info "Configuration:"
|
|
echo " Domain: $DOMAIN"
|
|
echo " Zone ID: $zone_id"
|
|
echo " Account ID: $account_id"
|
|
echo ""
|
|
|
|
# Tunnel configuration
|
|
declare -A TUNNELS=(
|
|
["ml110"]="ml110-01.d-bis.org:https://${PROXMOX_HOST_ML110}:8006"
|
|
["r630-01"]="r630-01.d-bis.org:https://${PROXMOX_HOST_R630_01}:8006"
|
|
["r630-02"]="r630-02.d-bis.org:https://${PROXMOX_HOST_R630_02}:8006"
|
|
)
|
|
|
|
echo "=========================================="
|
|
log_info "Step 1: Creating Tunnels"
|
|
echo "=========================================="
|
|
|
|
declare -A TUNNEL_IDS=()
|
|
declare -A TUNNEL_TOKENS=()
|
|
|
|
for tunnel_name in "${!TUNNELS[@]}"; do
|
|
local full_name="tunnel-${tunnel_name}"
|
|
|
|
# First, try to get existing tunnel
|
|
local response
|
|
response=$(cf_api_request "GET" "/accounts/${account_id}/cfd_tunnel" 2>/dev/null) || response=""
|
|
local tunnel_id=""
|
|
|
|
if [[ -n "$response" ]] && echo "$response" | jq -e '.result' >/dev/null 2>&1; then
|
|
tunnel_id=$(echo "$response" | jq -r ".result[]? | select(.name == \"${full_name}\") | .id" 2>/dev/null || echo "")
|
|
fi
|
|
|
|
# If not found, try to create
|
|
if [[ -z "$tunnel_id" ]] || [[ "$tunnel_id" == "null" ]] || [[ "$tunnel_id" == "" ]]; then
|
|
log_info "Tunnel $full_name not found, creating..."
|
|
tunnel_id=$(create_tunnel "$account_id" "$full_name")
|
|
else
|
|
log_success "Using existing tunnel: $full_name (ID: $tunnel_id)"
|
|
fi
|
|
|
|
if [[ -z "$tunnel_id" ]] || [[ "$tunnel_id" == "null" ]] || [[ "$tunnel_id" == "" ]]; then
|
|
log_error "Failed to get or create tunnel $full_name"
|
|
continue
|
|
fi
|
|
|
|
TUNNEL_IDS["$tunnel_name"]="$tunnel_id"
|
|
|
|
# Get token (optional - can be generated later via cloudflared CLI)
|
|
log_info "Attempting to generate token for tunnel $full_name..."
|
|
local token
|
|
token=$(get_tunnel_token "$account_id" "$tunnel_id" 2>/dev/null) || token=""
|
|
|
|
if [[ -z "$token" ]] || [[ "$token" == "null" ]]; then
|
|
log_warn "Could not generate token for $full_name via API"
|
|
log_info "Token can be generated later via: cloudflared tunnel token <tunnel-id>"
|
|
log_info "Or use cloudflared CLI: cloudflared tunnel create $full_name"
|
|
token=""
|
|
else
|
|
log_success "Token generated for $full_name"
|
|
fi
|
|
|
|
TUNNEL_TOKENS["$tunnel_name"]="$token"
|
|
|
|
echo ""
|
|
done
|
|
|
|
echo "=========================================="
|
|
log_info "Step 2: Configuring Tunnel Routes"
|
|
echo "=========================================="
|
|
|
|
for tunnel_name in "${!TUNNELS[@]}"; do
|
|
local config="${TUNNELS[$tunnel_name]}"
|
|
local hostname="${config%%:*}"
|
|
local service="${config#*:}"
|
|
local tunnel_id="${TUNNEL_IDS[$tunnel_name]}"
|
|
|
|
configure_tunnel_routes "$account_id" "$tunnel_id" "$hostname" "$service"
|
|
echo ""
|
|
done
|
|
|
|
echo "=========================================="
|
|
log_info "Step 3: Creating DNS Records"
|
|
echo "=========================================="
|
|
|
|
for tunnel_name in "${!TUNNELS[@]}"; do
|
|
local config="${TUNNELS[$tunnel_name]}"
|
|
local hostname="${config%%:*}"
|
|
local tunnel_id="${TUNNEL_IDS[$tunnel_name]}"
|
|
local target="${tunnel_id}.cfargotunnel.com"
|
|
|
|
create_dns_record "$zone_id" "$hostname" "$target"
|
|
echo ""
|
|
done
|
|
|
|
echo "=========================================="
|
|
log_info "Step 4: Creating Cloudflare Access Applications"
|
|
echo "=========================================="
|
|
|
|
for tunnel_name in "${!TUNNELS[@]}"; do
|
|
local config="${TUNNELS[$tunnel_name]}"
|
|
local hostname="${config%%:*}"
|
|
local app_name="Proxmox ${tunnel_name}"
|
|
local app_id=$(create_access_application "$account_id" "$app_name" "$hostname")
|
|
|
|
# Create policy
|
|
create_access_policy "$account_id" "$app_id"
|
|
echo ""
|
|
done
|
|
|
|
echo "=========================================="
|
|
log_success "Setup Complete!"
|
|
echo "=========================================="
|
|
echo ""
|
|
log_info "Tunnel IDs:"
|
|
for tunnel_name in "${!TUNNEL_IDS[@]}"; do
|
|
echo " $tunnel_name:"
|
|
echo " ID: ${TUNNEL_IDS[$tunnel_name]}"
|
|
if [[ -n "${TUNNEL_TOKENS[$tunnel_name]}" ]] && [[ "${TUNNEL_TOKENS[$tunnel_name]}" != "" ]]; then
|
|
echo " Token: ${TUNNEL_TOKENS[$tunnel_name]:0:50}..."
|
|
else
|
|
echo " Token: (not generated - use cloudflared CLI to generate)"
|
|
fi
|
|
done
|
|
|
|
# Save credentials to file for easy access
|
|
local creds_file="$TUNNELS_DIR/tunnel-credentials.json"
|
|
log_info ""
|
|
log_info "Saving credentials to: $creds_file"
|
|
|
|
local json_output="{"
|
|
local first=true
|
|
for tunnel_name in "${!TUNNEL_IDS[@]}"; do
|
|
if [[ "$first" == "true" ]]; then
|
|
first=false
|
|
else
|
|
json_output+=","
|
|
fi
|
|
json_output+="\"$tunnel_name\":{"
|
|
json_output+="\"id\":\"${TUNNEL_IDS[$tunnel_name]}\","
|
|
json_output+="\"token\":\"${TUNNEL_TOKENS[$tunnel_name]}\""
|
|
json_output+="}"
|
|
done
|
|
json_output+="}"
|
|
|
|
echo "$json_output" | jq . > "$creds_file"
|
|
chmod 600 "$creds_file"
|
|
log_success "Credentials saved to $creds_file"
|
|
|
|
echo ""
|
|
log_info "Next steps:"
|
|
echo " 1. Credentials saved to: $creds_file"
|
|
echo " 2. Run: ./scripts/save-credentials-from-file.sh"
|
|
echo " 3. Or manually: ./scripts/save-tunnel-credentials.sh <name> <id> <token>"
|
|
echo " 4. Start services: systemctl start cloudflared-*"
|
|
echo " 5. Test access: curl -I https://ml110-01.d-bis.org"
|
|
}
|
|
|
|
main
|
|
|