mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-11 13:47:05 +02:00
Adding development-containers that we used to develop fail2ban-ui, can also be used for easy and fast stack-testing
This commit is contained in:
166
development/oidc/init-keycloak.sh
Executable file
166
development/oidc/init-keycloak.sh
Executable file
@@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
# Automatic Keycloak OIDC client configuration script
|
||||
# This script creates the fail2ban-ui OIDC client in Keycloak automatically
|
||||
|
||||
set -e
|
||||
|
||||
KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:3000}"
|
||||
KEYCLOAK_ADMIN="${KEYCLOAK_ADMIN:-admin}"
|
||||
KEYCLOAK_PASSWORD="${KEYCLOAK_PASSWORD:-admin}"
|
||||
REALM="${REALM:-master}"
|
||||
CLIENT_ID="${CLIENT_ID:-fail2ban-ui}"
|
||||
CLIENT_SECRET="${CLIENT_SECRET:-}"
|
||||
# Use PUBLIC_FRONTEND_URL if provided, otherwise default to localhost
|
||||
PUBLIC_FRONTEND_URL="${PUBLIC_FRONTEND_URL:-http://localhost:3080}"
|
||||
REDIRECT_URI="${REDIRECT_URI:-${PUBLIC_FRONTEND_URL}/auth/callback}"
|
||||
WEB_ORIGIN="${WEB_ORIGIN:-${PUBLIC_FRONTEND_URL}}"
|
||||
|
||||
# Extract host and port from KEYCLOAK_URL for health check
|
||||
# KEYCLOAK_URL is the internal URL (e.g., http://keycloak:8080)
|
||||
# Health endpoint is on management port 9000
|
||||
KEYCLOAK_HOST=$(echo "${KEYCLOAK_URL}" | sed -E 's|https?://([^:/]+).*|\1|')
|
||||
KEYCLOAK_HEALTH_URL="http://${KEYCLOAK_HOST}:9000/health/ready"
|
||||
|
||||
echo "Waiting for Keycloak to be ready..."
|
||||
echo "Checking health endpoint: ${KEYCLOAK_HEALTH_URL}"
|
||||
max_attempts=120 # Increased timeout since Keycloak can take a while
|
||||
attempt=0
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check health endpoint on management port 9000
|
||||
if curl -s -f "${KEYCLOAK_HEALTH_URL}" > /dev/null 2>&1; then
|
||||
echo "Keycloak is ready!"
|
||||
break
|
||||
fi
|
||||
# Also try the main port as fallback
|
||||
if curl -s -f "${KEYCLOAK_URL}/health/ready" > /dev/null 2>&1; then
|
||||
echo "Keycloak is ready (via main port)!"
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
if [ $((attempt % 10)) -eq 0 ]; then
|
||||
echo "Attempt $attempt/$max_attempts: Keycloak not ready yet, waiting..."
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
echo "ERROR: Keycloak did not become ready in time"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Waiting for Keycloak admin API to be available..."
|
||||
sleep 5
|
||||
|
||||
echo "Getting admin access token..."
|
||||
ADMIN_TOKEN=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "username=${KEYCLOAK_ADMIN}" \
|
||||
-d "password=${KEYCLOAK_PASSWORD}" \
|
||||
-d "grant_type=password" \
|
||||
-d "client_id=admin-cli" | jq -r '.access_token')
|
||||
|
||||
if [ -z "$ADMIN_TOKEN" ] || [ "$ADMIN_TOKEN" = "null" ]; then
|
||||
echo "ERROR: Failed to get admin token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking if client already exists..."
|
||||
EXISTING_CLIENT=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${REALM}/clients?clientId=${CLIENT_ID}" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" | jq -r '.[0].id // empty')
|
||||
|
||||
if [ -n "$EXISTING_CLIENT" ]; then
|
||||
echo "Client '${CLIENT_ID}' already exists, updating..."
|
||||
CLIENT_UUID="$EXISTING_CLIENT"
|
||||
|
||||
# Update client configuration
|
||||
curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"clientId\": \"${CLIENT_ID}\",
|
||||
\"enabled\": true,
|
||||
\"clientAuthenticatorType\": \"client-secret\",
|
||||
\"redirectUris\": [\"${REDIRECT_URI}\"],
|
||||
\"webOrigins\": [\"${WEB_ORIGIN}\"],
|
||||
\"protocol\": \"openid-connect\",
|
||||
\"publicClient\": false,
|
||||
\"standardFlowEnabled\": true,
|
||||
\"directAccessGrantsEnabled\": true
|
||||
}" > /dev/null
|
||||
|
||||
echo "Client updated successfully"
|
||||
else
|
||||
echo "Creating new client '${CLIENT_ID}'..."
|
||||
|
||||
# Create client
|
||||
CLIENT_RESPONSE=$(curl -s -X POST "${KEYCLOAK_URL}/admin/realms/${REALM}/clients" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"clientId\": \"${CLIENT_ID}\",
|
||||
\"enabled\": true,
|
||||
\"clientAuthenticatorType\": \"client-secret\",
|
||||
\"redirectUris\": [\"${REDIRECT_URI}\"],
|
||||
\"webOrigins\": [\"${WEB_ORIGIN}\"],
|
||||
\"protocol\": \"openid-connect\",
|
||||
\"publicClient\": false,
|
||||
\"standardFlowEnabled\": true,
|
||||
\"directAccessGrantsEnabled\": true
|
||||
}")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Failed to create client"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the client UUID
|
||||
CLIENT_UUID=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${REALM}/clients?clientId=${CLIENT_ID}" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" | jq -r '.[0].id')
|
||||
|
||||
echo "Client created successfully with UUID: ${CLIENT_UUID}"
|
||||
fi
|
||||
|
||||
# Get or regenerate client secret
|
||||
echo "Getting client secret..."
|
||||
CLIENT_SECRET=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/client-secret" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" | jq -r '.value')
|
||||
|
||||
if [ -z "$CLIENT_SECRET" ] || [ "$CLIENT_SECRET" = "null" ]; then
|
||||
echo "Regenerating client secret..."
|
||||
CLIENT_SECRET=$(curl -s -X POST "${KEYCLOAK_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/client-secret" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-H "Content-Type: application/json" | jq -r '.value')
|
||||
fi
|
||||
|
||||
if [ -z "$CLIENT_SECRET" ] || [ "$CLIENT_SECRET" = "null" ]; then
|
||||
echo "ERROR: Failed to get client secret"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "OIDC Client Configuration Complete!"
|
||||
echo "=========================================="
|
||||
echo "Client ID: ${CLIENT_ID}"
|
||||
echo "Client Secret: ${CLIENT_SECRET}"
|
||||
echo "Realm: ${REALM}"
|
||||
echo "Redirect URI: ${REDIRECT_URI}"
|
||||
echo "=========================================="
|
||||
|
||||
# Save secret to shared volume for fail2ban-ui to read
|
||||
SECRET_FILE="${SECRET_FILE:-/config/keycloak-client-secret}"
|
||||
# Create directory if it doesn't exist
|
||||
mkdir -p "$(dirname "${SECRET_FILE}")" 2>/dev/null || true
|
||||
# Write secret file (running as root, so should have permissions)
|
||||
if echo "${CLIENT_SECRET}" > "${SECRET_FILE}" 2>/dev/null; then
|
||||
chmod 644 "${SECRET_FILE}" 2>/dev/null || true
|
||||
echo "Client secret saved to ${SECRET_FILE} for fail2ban-ui"
|
||||
else
|
||||
echo "ERROR: Failed to write client secret to ${SECRET_FILE}"
|
||||
echo "Client secret: ${CLIENT_SECRET}"
|
||||
echo "Please save this secret manually to ${SECRET_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user