Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions src/docker/TENANT_MANAGEMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Tenant Management for RelayServer

## Overview

This document describes how to manage tenants in the Keycloak identity provider for RelayServer.

## Prerequisites

1. Keycloak container must be running (`relay-identityprovider`)
2. The `keycloak-admin` client must be configured in the realm (already included in the updated `relayserver-realm.json`)

## Creating New Tenants

### Using the Shell Script

The `create-tenant.sh` script allows you to create new tenant clients via the Keycloak API.

#### Usage

```bash
./create-tenant.sh <tenant_name> <display_name> [description] [client_secret]
```

#### Parameters

- `tenant_name` (required): The unique identifier for the tenant (e.g., `TestTenant3`)
- `display_name` (required): Human-readable name for the tenant (e.g., `"Test Tenant 3"`)
- `description` (optional): Description of the tenant (default: "Tenant client for RelayServer")
- `client_secret` (optional): The client secret to use (default: `<Strong!Passw0rd>`)

#### Examples

Create a tenant with default settings:
```bash
./create-tenant.sh TestTenant3 "Test Tenant 3"
```

Create a tenant with custom description and secret:
```bash
./create-tenant.sh MyTenant "My Custom Tenant" "Production tenant for ACME Corp" "MySecurePassword123!"
```

#### Environment Variables

- `KEYCLOAK_URL`: The Keycloak server URL (default: `http://localhost:5002`)
- `ADMIN_CLIENT_SECRET`: The keycloak-admin client secret (default: `<Strong!Passw0rd>`)

Example with custom Keycloak URL:
```bash
KEYCLOAK_URL=http://keycloak.example.com:8080 ./create-tenant.sh TestTenant4 "Test Tenant 4"
```

## What the Script Does

1. **Authenticates**: Obtains an access token using the `keycloak-admin` service account
2. **Creates Client**: Creates a new OAuth2/OIDC client with the specified configuration
3. **Configures Permissions**: Assigns the `Access-To-RelayServer` role to the client's service account
4. **Sets up Protocol Mappers**: Configures client IP, client ID, and client host mappers

The created client will have:
- Service accounts enabled
- Client credentials grant type
- The same configuration as TestTenant1 and TestTenant2
- Access to the RelayServer via the assigned role

## Using the New Tenant

After creating a tenant, you can use it with a connector by setting these environment variables:

```yaml
environment:
RelayConnector__TenantName: YourTenantName
RelayConnector__RelayServerBaseUri: http://relay-server-a:5000
```

Or in a docker-compose service:

```yaml
my-connector:
image: relay-connector
environment:
RelayConnector__TenantName: TestTenant3
RelayConnector__RelayServerBaseUri: http://relay-server-a:5000
# ... other configuration
```

## Manual Tenant Creation via Keycloak Admin Console

If you prefer to create tenants manually:

1. Access Keycloak Admin Console at `http://localhost:5002`
2. Login with admin/admin
3. Select the `relayserver` realm
4. Go to Clients → Create client
5. Configure the client with:
- Client type: OpenID Connect
- Client ID: Your tenant name
- Client authentication: ON
- Service accounts roles: ON
- Standard flow: OFF
- Direct access grants: OFF
6. Save and configure the client secret
7. Go to the Service accounts roles tab
8. Assign the `Access-To-RelayServer` role from the `relayserver` client

## Keycloak Admin Client Details

The `keycloak-admin` client is configured with the following permissions:
- `manage-clients`: Manage all clients in the realm
- `create-client`: Create new clients
- `view-clients`: View client configurations
- `query-clients`: Query for clients
- `view-realm`: View realm configuration
- `manage-users`: Manage users (needed for service account configuration)
- `view-users`: View users
- `query-users`: Query for users

This client uses service account authentication with the client credentials grant type.

## Security Notes

1. The default password `<Strong!Passw0rd>` should only be used in demo/development environments
2. In production, use strong, unique passwords for each tenant
3. The `keycloak-admin` client has elevated privileges - protect its credentials carefully
4. Consider implementing additional security measures like:
- IP restrictions
- Short token lifetimes
- Audit logging
- Regular credential rotation

## Troubleshooting

### Script fails to get access token
- Check that Keycloak is running and accessible
- Verify the KEYCLOAK_URL is correct
- Ensure the keycloak-admin client exists and has the correct secret

### Client creation succeeds but role assignment fails
- The service account may take a moment to be created - the script waits 2 seconds
- Check that the `relayserver` client exists in the realm
- Verify the `Access-To-RelayServer` role exists

### Connector can't authenticate with new tenant
- Verify the tenant was created successfully in Keycloak
- Check that the service account has the `Access-To-RelayServer` role
- Ensure the client secret matches what's configured in the connector
153 changes: 153 additions & 0 deletions src/docker/check-keycloak-admin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/bin/bash

# Diagnostic script to check keycloak-admin client configuration
# Usage: ./check-keycloak-admin.sh

set -e

# Configuration
KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:5002}"
REALM="relayserver"
ADMIN_CLIENT_ID="keycloak-admin"
ADMIN_CLIENT_SECRET="${ADMIN_CLIENT_SECRET:-<Strong!Passw0rd>}"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to print colored messages
print_message() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}

print_message "$BLUE" "========================================="
print_message "$BLUE" "Keycloak Admin Client Diagnostic"
print_message "$BLUE" "========================================="
echo ""

# Check Keycloak availability
print_message "$YELLOW" "1. Checking Keycloak availability..."
if curl -s -f -o /dev/null "${KEYCLOAK_URL}/realms/${REALM}/.well-known/openid-configuration"; then
print_message "$GREEN" " ✓ Keycloak is accessible at ${KEYCLOAK_URL}"
else
print_message "$RED" " ✗ Cannot reach Keycloak at ${KEYCLOAK_URL}"
print_message "$RED" " Please ensure Docker containers are running"
exit 1
fi

# Try to get token
print_message "$YELLOW" "2. Testing authentication with keycloak-admin client..."
token_response=$(curl -s -X POST \
"${KEYCLOAK_URL}/realms/${REALM}/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=${ADMIN_CLIENT_ID}" \
-d "client_secret=${ADMIN_CLIENT_SECRET}")

access_token=$(echo "$token_response" | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//')

if [ -n "$access_token" ]; then
print_message "$GREEN" " ✓ Successfully authenticated"

# Decode token to check roles (if jq is available)
if command -v jq >/dev/null 2>&1 && command -v base64 >/dev/null 2>&1; then
print_message "$YELLOW" "3. Checking token permissions..."
token_payload=$(echo "$access_token" | cut -d. -f2 | base64 -d 2>/dev/null | jq . 2>/dev/null || echo "{}")

# Check for realm-management roles
realm_roles=$(echo "$token_payload" | jq -r '.resource_access."realm-management".roles[]?' 2>/dev/null)

if [ -n "$realm_roles" ]; then
print_message "$GREEN" " ✓ Found realm-management roles:"
echo "$realm_roles" | while read -r role; do
echo " - $role"
done
else
print_message "$YELLOW" " ⚠ No realm-management roles found in token"
fi
fi
else
print_message "$RED" " ✗ Failed to authenticate"
error_msg=$(echo "$token_response" | grep -o '"error_description":"[^"]*' | sed 's/"error_description":"//')
if [ -n "$error_msg" ]; then
print_message "$RED" " Error: $error_msg"
else
print_message "$RED" " Response: $token_response"
fi
echo ""
print_message "$YELLOW" " Possible causes:"
echo " - The keycloak-admin client may not exist"
echo " - The client secret may be incorrect"
echo " - Keycloak may still be initializing"
exit 1
fi

# Test API access
print_message "$YELLOW" "4. Testing Admin API access..."

# Try to list clients
list_response=$(curl -s -w "\n%{http_code}" -X GET \
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients?max=1" \
-H "Authorization: Bearer ${access_token}")

http_code=$(echo "$list_response" | tail -n1)

if [ "$http_code" = "200" ]; then
print_message "$GREEN" " ✓ Can list clients (HTTP 200)"
else
print_message "$RED" " ✗ Cannot list clients (HTTP ${http_code})"
response_body=$(echo "$list_response" | sed '$d')
if [ -n "$response_body" ]; then
print_message "$RED" " Response: $response_body"
fi
fi

# Try to check create permission
print_message "$YELLOW" "5. Checking create client permission..."
# We'll do a dry-run by sending an invalid request that should fail with 400 (bad request) not 403 (forbidden)
create_test=$(curl -s -w "\n%{http_code}" -X POST \
"${KEYCLOAK_URL}/admin/realms/${REALM}/clients" \
-H "Authorization: Bearer ${access_token}" \
-H "Content-Type: application/json" \
-d '{}')

http_code=$(echo "$create_test" | tail -n1)

if [ "$http_code" = "400" ]; then
print_message "$GREEN" " ✓ Has permission to create clients (got expected 400 for invalid request)"
elif [ "$http_code" = "403" ]; then
print_message "$RED" " ✗ No permission to create clients (HTTP 403 Forbidden)"
print_message "$RED" " The keycloak-admin client needs realm-admin permissions"
else
print_message "$YELLOW" " ⚠ Unexpected response code: HTTP ${http_code}"
fi

echo ""
print_message "$BLUE" "========================================="
print_message "$BLUE" "Diagnostic Complete"
print_message "$BLUE" "========================================="

if [ "$http_code" = "400" ] || [ "$http_code" = "201" ]; then
echo ""
print_message "$GREEN" "✓ The keycloak-admin client appears to be configured correctly!"
echo ""
echo "You can now create tenants using:"
echo " ./create-tenant.sh <tenant_name> <display_name> [description] [secret]"
else
echo ""
print_message "$YELLOW" "⚠ There may be permission issues with the keycloak-admin client."
echo ""
echo "To fix this:"
echo "1. Stop the Docker containers: docker-compose down"
echo "2. Start them again: docker-compose up -d"
echo "3. Wait about 30 seconds for Keycloak to initialize"
echo "4. Run this diagnostic again"
echo ""
echo "If the problem persists, check the realm configuration in:"
echo " keycloak_data/relayserver-realm.json"
fi
Loading