ab.dem.tf.changemaker/add-cname-records.sh
2025-05-30 12:43:55 -06:00

291 lines
9.6 KiB
Bash
Executable File

#!/bin/bash
echo "#############################################################"
echo "# "
echo "# DNS Setup for Changemaker.lite Services "
echo "# "
echo "# This script will ADD DNS records for your services. "
echo "# Existing DNS records will NOT be deleted. "
echo "# "
echo "#############################################################"
echo ""
echo "-------------------------------------------------------------"
echo "Cloudflare Credentials Required"
echo "Please ensure your .env file contains the following variables:"
echo " CF_API_TOKEN=your_cloudflare_api_token"
echo " CF_ZONE_ID=your_cloudflare_zone_id"
echo " CF_TUNNEL_ID=your_cloudflared_tunnel_id"
echo " CF_DOMAIN=yourdomain.com"
echo ""
echo "You can find these values in your Cloudflare dashboard:"
echo " - API Token: https://dash.cloudflare.com/profile/api-tokens (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions for your domain)"
echo " - Zone ID: On your domain's overview page"
echo " - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels"
echo " - Domain: The domain you want to use for your services"
echo ""
echo "-------------------------------------------------------------"
echo ""
read -p "Type 'y' to continue or any other key to abort: " consent
if [[ "$consent" != "y" && "$consent" != "Y" ]]; then
echo "Aborted by user."
exit 1
fi
# Source environment variables from the .env file in the same directory
ENV_FILE="$(dirname "$0")/.env"
if [ -f "$ENV_FILE" ]; then
export $(grep -v '^#' "$ENV_FILE" | xargs)
else
echo "Error: .env file not found at $ENV_FILE"
exit 1
fi
# Check if required Cloudflare variables are set
if [ -z "$CF_API_TOKEN" ] || [ -z "$CF_ZONE_ID" ] || [ -z "$CF_TUNNEL_ID" ] || [ -z "$CF_DOMAIN" ]; then
echo "Error: One or more required Cloudflare environment variables (CF_API_TOKEN, CF_ZONE_ID, CF_TUNNEL_ID, CF_DOMAIN) are not set in $ENV_FILE."
exit 1
fi
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo "Error: jq is required but not installed. Please install jq to continue."
echo "On Debian/Ubuntu: sudo apt-get install jq"
echo "On RHEL/CentOS: sudo yum install jq"
exit 1
fi
# Array of subdomains that need DNS records - updated to match our active services
SUBDOMAINS=(
"dashboard"
"code"
"listmonk"
"docs"
"n8n"
"db"
"git"
)
# Function to check if DNS record already exists
record_exists() {
local subdomain=$1
local records=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?name=$subdomain.$CF_DOMAIN" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json")
local count=$(echo $records | jq -r '.result | length')
[ "$count" -gt 0 ]
}
# Add CNAME records for each subdomain (only if they don't exist)
echo "Adding DNS records for services..."
for subdomain in "${SUBDOMAINS[@]}"; do
if record_exists "$subdomain"; then
echo "DNS record for $subdomain.$CF_DOMAIN already exists, skipping..."
else
echo "Adding CNAME record for $subdomain.$CF_DOMAIN..."
response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"CNAME\",
\"name\": \"$subdomain\",
\"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
\"ttl\": 1,
\"proxied\": true
}")
success=$(echo $response | jq -r '.success')
if [ "$success" == "true" ]; then
echo "✓ Successfully added CNAME record for $subdomain.$CF_DOMAIN"
else
echo "✗ Failed to add CNAME record for $subdomain.$CF_DOMAIN"
echo "Error: $(echo $response | jq -r '.errors[0].message')"
fi
fi
done
# Add root domain record if it doesn't exist
if record_exists "@"; then
echo "Root domain DNS record already exists, skipping..."
else
echo "Adding root domain CNAME record..."
response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"CNAME\",
\"name\": \"@\",
\"content\": \"$CF_TUNNEL_ID.cfargotunnel.com\",
\"ttl\": 1,
\"proxied\": true
}")
success=$(echo $response | jq -r '.success')
if [ "$success" == "true" ]; then
echo "✓ Successfully added root domain CNAME record"
else
echo "✗ Failed to add root domain CNAME record"
echo "Error: $(echo $response | jq -r '.errors[0].message')"
fi
fi
echo ""
echo "DNS records setup complete!"
echo ""
# Prompt for admin email for secured services
echo "-------------------------------------------------------------"
echo "Setting up Cloudflare Access Protection"
echo "-------------------------------------------------------------"
echo ""
echo "The following services will be protected with authentication:"
echo " - dashboard.$CF_DOMAIN"
echo " - code.$CF_DOMAIN"
echo ""
echo "Please enter the admin email address that should have access:"
read ADMIN_EMAIL
# Validate email format
if [[ ! "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Error: Invalid email format. Please provide a valid email address."
exit 1
fi
# Services that require authentication - updated for our use case
PROTECTED_SERVICES=("dashboard" "code")
# Services that should have bypass policies (public access) - updated for our use case
BYPASS_SERVICES=("listmonk" "docs" "n8n" "db" "git")
# Function to create access application with email authentication
create_protected_app() {
local service=$1
echo "Setting up authentication for $service.$CF_DOMAIN..."
app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"name\": \"$service $CF_DOMAIN\",
\"domain\": \"$service.$CF_DOMAIN\",
\"type\": \"self_hosted\",
\"session_duration\": \"24h\",
\"app_launcher_visible\": true,
\"skip_interstitial\": true
}")
app_id=$(echo $app_response | jq -r '.result.id')
if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then
echo "✗ Error creating access application for $service"
return 1
fi
echo "✓ Created access application for $service (ID: $app_id)"
# Create authentication policy
policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"name\": \"Admin Access\",
\"decision\": \"allow\",
\"include\": [{
\"email\": {
\"email\": \"$ADMIN_EMAIL\"
}
}],
\"require\": [],
\"exclude\": []
}")
policy_success=$(echo $policy_response | jq -r '.success')
if [ "$policy_success" == "true" ]; then
echo "✓ Created authentication policy for $service"
else
echo "✗ Failed to create authentication policy for $service"
fi
}
# Function to create bypass application (public access)
create_bypass_app() {
local service=$1
echo "Setting up public access for $service.$CF_DOMAIN..."
app_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"name\": \"$service $CF_DOMAIN\",
\"domain\": \"$service.$CF_DOMAIN\",
\"type\": \"self_hosted\",
\"session_duration\": \"24h\",
\"app_launcher_visible\": false,
\"skip_interstitial\": true
}")
app_id=$(echo $app_response | jq -r '.result.id')
if [ -z "$app_id" ] || [ "$app_id" == "null" ]; then
echo "✗ Error creating access application for $service"
return 1
fi
echo "✓ Created access application for $service (ID: $app_id)"
# Create bypass policy
policy_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/access/apps/$app_id/policies" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data "{
\"name\": \"Public Access\",
\"decision\": \"bypass\",
\"include\": [{
\"everyone\": {}
}],
\"require\": [],
\"exclude\": []
}")
policy_success=$(echo $policy_response | jq -r '.success')
if [ "$policy_success" == "true" ]; then
echo "✓ Created public access policy for $service"
else
echo "✗ Failed to create public access policy for $service"
fi
}
echo "Creating Cloudflare Access applications..."
echo ""
# Create protected applications
for service in "${PROTECTED_SERVICES[@]}"; do
create_protected_app "$service"
echo ""
done
# Create bypass applications for public services
for service in "${BYPASS_SERVICES[@]}"; do
create_bypass_app "$service"
echo ""
done
echo "-------------------------------------------------------------"
echo "Setup Complete!"
echo "-------------------------------------------------------------"
echo ""
echo "Protected services (require authentication with $ADMIN_EMAIL):"
for service in "${PROTECTED_SERVICES[@]}"; do
echo " - https://$service.$CF_DOMAIN"
done
echo ""
echo "Public services (no authentication required):"
for service in "${BYPASS_SERVICES[@]}"; do
echo " - https://$service.$CF_DOMAIN"
done
echo ""
echo "All services should be accessible through your Cloudflare tunnel."