Skip to content
Merged
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
2 changes: 2 additions & 0 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ module server 'server.bicep' = {
exists: serverExists
// Keycloak authentication configuration (only when enabled)
keycloakRealmUrl: useKeycloak ? '${keycloak!.outputs.uri}/realms/${keycloakRealmName}' : ''
keycloakTokenIssuer: useKeycloak ? '${keycloakMcpServerBaseUrl}/realms/${keycloakRealmName}' : ''
keycloakMcpServerBaseUrl: useKeycloak ? keycloakMcpServerBaseUrl : ''
keycloakMcpServerAudience: keycloakMcpServerAudience
// Azure/Entra ID OAuth Proxy authentication configuration (only when enabled)
Expand Down Expand Up @@ -913,6 +914,7 @@ output KEYCLOAK_MCP_SERVER_BASE_URL string = useKeycloak ? keycloakMcpServerBase
output KEYCLOAK_REALM_URL string = useKeycloak ? '${httpRoutes!.outputs.routeConfigUrl}/auth/realms/${keycloakRealmName}' : ''
output KEYCLOAK_ADMIN_CONSOLE string = useKeycloak ? '${httpRoutes!.outputs.routeConfigUrl}/auth/admin' : ''
output KEYCLOAK_DIRECT_URL string = keycloak.outputs.uri
output KEYCLOAK_TOKEN_ISSUER string = useKeycloak ? '${keycloakMcpServerBaseUrl}/realms/${keycloakRealmName}' : ''

// Auth provider for env scripts
output MCP_AUTH_PROVIDER string = mcpAuthProvider
5 changes: 5 additions & 0 deletions infra/server.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ param cosmosDbUserContainer string
param cosmosDbOAuthContainer string
param applicationInsightsConnectionString string = ''
param keycloakRealmUrl string = ''
param keycloakTokenIssuer string = ''
param keycloakMcpServerAudience string = 'mcp-server'
param keycloakMcpServerBaseUrl string = ''
param entraProxyClientId string = ''
Expand Down Expand Up @@ -91,6 +92,10 @@ var keycloakEnv = !empty(keycloakRealmUrl) ? [
name: 'KEYCLOAK_REALM_URL'
value: keycloakRealmUrl
}
{
name: 'KEYCLOAK_TOKEN_ISSUER'
value: !empty(keycloakTokenIssuer) ? keycloakTokenIssuer : keycloakRealmUrl
}
{
name: 'KEYCLOAK_MCP_SERVER_AUDIENCE'
value: keycloakMcpServerAudience
Expand Down
42 changes: 36 additions & 6 deletions infra/write_env.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
# Define the .env file path
$ENV_FILE_PATH = ".env"


# Returns empty string if value not found or contains ERROR
function Get-AzdValue {
param([string]$Key)
$value = azd env get-value $Key 2>$null
if ($value -and $value.Contains("ERROR:")) {
return ""
}
return $value
}

# Write a required env var (always written)
function Write-Env {
param([string]$Key)
Add-Content -Path $ENV_FILE_PATH -Value "$Key=$(Get-AzdValue $Key)"
}

# Write an optional env var (only written if value is non-empty)
function Write-EnvIfSet {
param([string]$Key)
$value = Get-AzdValue $Key
if ($value -and $value -ne "") {
Add-Content -Path $ENV_FILE_PATH -Value "$Key=$value"
}
}

# Clear the contents of the .env file
Set-Content -Path $ENV_FILE_PATH -Value $null

Expand All @@ -14,17 +40,21 @@ Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_CONTAINER=$(azd env get-
Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_USER_CONTAINER=$(azd env get-value AZURE_COSMOSDB_USER_CONTAINER)"
Add-Content -Path $ENV_FILE_PATH -Value "AZURE_COSMOSDB_OAUTH_CONTAINER=$(azd env get-value AZURE_COSMOSDB_OAUTH_CONTAINER)"
Add-Content -Path $ENV_FILE_PATH -Value "APPLICATIONINSIGHTS_CONNECTION_STRING=$(azd env get-value APPLICATIONINSIGHTS_CONNECTION_STRING)"
Add-Content -Path $ENV_FILE_PATH -Value "MCP_AUTH_PROVIDER=$(azd env get-value MCP_AUTH_PROVIDER)"
$KEYCLOAK_REALM_URL = azd env get-value KEYCLOAK_REALM_URL 2>$null
Write-Env MCP_AUTH_PROVIDER

# Keycloak-related env vars (only if KEYCLOAK_REALM_URL is set)
$KEYCLOAK_REALM_URL = Get-AzdValue KEYCLOAK_REALM_URL
if ($KEYCLOAK_REALM_URL -and $KEYCLOAK_REALM_URL -ne "") {
Add-Content -Path $ENV_FILE_PATH -Value "KEYCLOAK_REALM_URL=$KEYCLOAK_REALM_URL"
Write-EnvIfSet KEYCLOAK_TOKEN_ISSUER
}
$ENTRA_PROXY_AZURE_CLIENT_ID = azd env get-value ENTRA_PROXY_AZURE_CLIENT_ID 2>$null

# Entra proxy env vars (only if ENTRA_PROXY_AZURE_CLIENT_ID is set)
$ENTRA_PROXY_AZURE_CLIENT_ID = Get-AzdValue ENTRA_PROXY_AZURE_CLIENT_ID
if ($ENTRA_PROXY_AZURE_CLIENT_ID -and $ENTRA_PROXY_AZURE_CLIENT_ID -ne "") {
Add-Content -Path $ENV_FILE_PATH -Value "ENTRA_PROXY_AZURE_CLIENT_ID=$ENTRA_PROXY_AZURE_CLIENT_ID"
Add-Content -Path $ENV_FILE_PATH -Value "ENTRA_PROXY_AZURE_CLIENT_SECRET=$(azd env get-value ENTRA_PROXY_AZURE_CLIENT_SECRET)"
$ENTRA_PROXY_MCP_SERVER_BASE_URL = azd env get-value ENTRA_PROXY_MCP_SERVER_BASE_URL 2>$null
Add-Content -Path $ENV_FILE_PATH -Value "ENTRA_PROXY_MCP_SERVER_BASE_URL=$ENTRA_PROXY_MCP_SERVER_BASE_URL"
Write-Env ENTRA_PROXY_AZURE_CLIENT_SECRET
Write-Env ENTRA_PROXY_MCP_SERVER_BASE_URL
}
Add-Content -Path $ENV_FILE_PATH -Value "MCP_ENTRY=$(azd env get-value MCP_ENTRY)"
Add-Content -Path $ENV_FILE_PATH -Value "MCP_SERVER_URL=$(azd env get-value MCP_SERVER_URL)"
Expand Down
47 changes: 40 additions & 7 deletions infra/write_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,34 @@ set -e
# Define the .env file path
ENV_FILE_PATH=".env"

# Returns empty string if value not found or contains ERROR
get_azd_value() {
local key="$1"
local value
value=$(azd env get-value "$key" 2>/dev/null || echo "")
if [[ "$value" == *ERROR:* ]]; then
echo ""
else
echo "$value"
fi
}

# Write a required env var (always written)
write_env() {
local key="$1"
echo "${key}=$(get_azd_value "$key")" >> "$ENV_FILE_PATH"
}

# Write an optional env var (only written if value is non-empty)
write_env_if_set() {
local key="$1"
local value
value=$(get_azd_value "$key")
if [ -n "$value" ]; then
echo "${key}=${value}" >> "$ENV_FILE_PATH"
fi
}

# Clear the contents of the .env file
> "$ENV_FILE_PATH"

Expand All @@ -18,16 +46,21 @@ echo "AZURE_COSMOSDB_CONTAINER=$(azd env get-value AZURE_COSMOSDB_CONTAINER)" >>
echo "AZURE_COSMOSDB_USER_CONTAINER=$(azd env get-value AZURE_COSMOSDB_USER_CONTAINER)" >> "$ENV_FILE_PATH"
echo "AZURE_COSMOSDB_OAUTH_CONTAINER=$(azd env get-value AZURE_COSMOSDB_OAUTH_CONTAINER)" >> "$ENV_FILE_PATH"
echo "APPLICATIONINSIGHTS_CONNECTION_STRING=$(azd env get-value APPLICATIONINSIGHTS_CONNECTION_STRING)" >> "$ENV_FILE_PATH"
echo "MCP_AUTH_PROVIDER=$(azd env get-value MCP_AUTH_PROVIDER)" >> "$ENV_FILE_PATH"
KEYCLOAK_REALM_URL=$(azd env get-value KEYCLOAK_REALM_URL 2>/dev/null || echo "")
if [ -n "$KEYCLOAK_REALM_URL" ] && [ "$KEYCLOAK_REALM_URL" != "" ]; then
write_env MCP_AUTH_PROVIDER

# Keycloak-related env vars (only if KEYCLOAK_REALM_URL is set)
KEYCLOAK_REALM_URL=$(get_azd_value KEYCLOAK_REALM_URL)
if [ -n "$KEYCLOAK_REALM_URL" ]; then
echo "KEYCLOAK_REALM_URL=${KEYCLOAK_REALM_URL}" >> "$ENV_FILE_PATH"
write_env_if_set KEYCLOAK_TOKEN_ISSUER
fi
ENTRA_PROXY_AZURE_CLIENT_ID=$(azd env get-value ENTRA_PROXY_AZURE_CLIENT_ID 2>/dev/null || echo "")
if [ -n "$ENTRA_PROXY_AZURE_CLIENT_ID" ] && [ "$ENTRA_PROXY_AZURE_CLIENT_ID" != "" ]; then

# Entra proxy env vars (only if ENTRA_PROXY_AZURE_CLIENT_ID is set)
ENTRA_PROXY_AZURE_CLIENT_ID=$(get_azd_value ENTRA_PROXY_AZURE_CLIENT_ID)
if [ -n "$ENTRA_PROXY_AZURE_CLIENT_ID" ]; then
echo "ENTRA_PROXY_AZURE_CLIENT_ID=${ENTRA_PROXY_AZURE_CLIENT_ID}" >> "$ENV_FILE_PATH"
echo "ENTRA_PROXY_AZURE_CLIENT_SECRET=$(azd env get-value ENTRA_PROXY_AZURE_CLIENT_SECRET)" >> "$ENV_FILE_PATH"
echo "ENTRA_PROXY_MCP_SERVER_BASE_URL=$(azd env get-value ENTRA_PROXY_MCP_SERVER_BASE_URL)" >> "$ENV_FILE_PATH"
write_env ENTRA_PROXY_AZURE_CLIENT_SECRET
write_env ENTRA_PROXY_MCP_SERVER_BASE_URL
fi
echo "MCP_ENTRY=$(azd env get-value MCP_ENTRY)" >> "$ENV_FILE_PATH"
echo "MCP_SERVER_URL=$(azd env get-value MCP_SERVER_URL)" >> "$ENV_FILE_PATH"
Expand Down
3 changes: 2 additions & 1 deletion servers/auth_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@
elif mcp_auth_provider == "keycloak":
# Keycloak authentication using RemoteAuthProvider with JWT verification
KEYCLOAK_REALM_URL = os.environ["KEYCLOAK_REALM_URL"]
KEYCLOAK_TOKEN_ISSUER = os.getenv("KEYCLOAK_TOKEN_ISSUER", KEYCLOAK_REALM_URL)
token_verifier = JWTVerifier(
jwks_uri=f"{KEYCLOAK_REALM_URL}/protocol/openid-connect/certs",
issuer=KEYCLOAK_REALM_URL,
issuer=KEYCLOAK_TOKEN_ISSUER,
audience=os.getenv("KEYCLOAK_MCP_SERVER_AUDIENCE", "mcp-server"),
)
# Prefer specific base URL env for Keycloak when provided
Expand Down
Loading