Appearance
Keycloak Deployment
Keycloak runs as a container in the Public CAE (Container Apps Environment). It is internet-accessible via Azure Front Door and handles SSO for all ERP frontend apps and mobile clients. This page covers the container image, SPI JAR deployment, realm import, and environment variables.
Architecture Placement
Keycloak shares the Public CAE with the Gateway.API. Both are behind Azure Front Door with separate custom domain routing rules.
Container Image
Microtec uses a custom Keycloak image built on top of the official quay.io/keycloak/keycloak base. The custom image bundles:
- The 7 SPI JARs (providers)
- Custom login themes (RTL + BO)
- Pre-configured realm export files (seeding)
Dockerfile
dockerfile
FROM quay.io/keycloak/keycloak:26.2.4
# ── SPI Providers ────────────────────────────────────────────
COPY providers/keycloak-multiaccount-spi-*.jar /opt/keycloak/providers/
COPY providers/keycloak-seeding-*.jar /opt/keycloak/providers/
COPY providers/keycloak-phone-email-auth-*.jar /opt/keycloak/providers/
COPY providers/keycloak-company-branch-mapper-*.jar /opt/keycloak/providers/
COPY providers/keycloak-erp-policy-mapper-*.jar /opt/keycloak/providers/
COPY providers/keycloak-tenant-validator-*.jar /opt/keycloak/providers/
COPY providers/keycloak-mac-cookie-*.jar /opt/keycloak/providers/
# ── Custom Themes ─────────────────────────────────────────────
COPY themes/microtec-rtl /opt/keycloak/themes/microtec-rtl
COPY themes/microtec-bo /opt/keycloak/themes/microtec-bo
COPY themes/microtec-email /opt/keycloak/themes/microtec-email
# ── Seed Configuration ────────────────────────────────────────
COPY seed/realm-microtec.json /opt/keycloak/seed/realm-microtec.json
COPY seed/realm-businessowner.json /opt/keycloak/seed/realm-businessowner.json
# Build optimized distribution
RUN /opt/keycloak/bin/kc.sh build \
--db=mssql \
--features=persistent-user-sessions,token-exchange,admin-fine-grained-authz:v1
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
CMD ["start", "--optimized"]Optimized Build
The kc.sh build step runs at image build time (not at container startup). This significantly reduces Keycloak startup time — from ~60 seconds to ~15 seconds. The --optimized flag at startup skips the build phase.
Image Tagging
Images are pushed to the environment's ACR with the same tagging convention as backend services:
| Environment | Tag Pattern | Example |
|---|---|---|
| dev / stage | {branch}-{build-id} | main-1042 |
| preprod / uat | {version}-rc{n} | 26.2.4-rc2 |
| production | {version} | 26.2.4 |
Container App Configuration
bicep
// keycloak.bicep
resource keycloakApp 'Microsoft.App/containerApps@2023-05-01' = {
name: 'keycloak'
location: location
properties: {
managedEnvironmentId: publicCaeId
configuration: {
ingress: {
external: true
targetPort: 8080
transport: 'http'
customDomains: [
{
name: 'auth.${environmentDomain}'
certificateId: wildcardCertId
}
]
}
registries: [
{
server: '${acrName}.azurecr.io'
identity: managedIdentityId
}
]
secrets: [
{
name: 'db-password'
keyVaultUrl: 'https://${kvName}.vault.azure.net/secrets/Keycloak--DbPassword'
identity: managedIdentityId
}
{
name: 'admin-password'
keyVaultUrl: 'https://${kvName}.vault.azure.net/secrets/Keycloak--AdminPassword'
identity: managedIdentityId
}
]
}
template: {
scale: {
minReplicas: 1
maxReplicas: 3
rules: [
{
name: 'http-scale'
http: { metadata: { concurrentRequests: '30' } }
}
]
}
containers: [
{
name: 'keycloak'
image: '${acrName}.azurecr.io/keycloak:${imageTag}'
resources: { cpu: json('1.0'), memory: '2Gi' }
env: [/* see Environment Variables section */]
}
]
}
}
}Environment Variables
Required (all environments)
| Variable | Source | Description |
|---|---|---|
KC_DB | Static | mssql |
KC_DB_URL | Bicep param | JDBC URL: jdbc:sqlserver://{host};databaseName=Microtec.SSO |
KC_DB_USERNAME | Static | sa |
KC_DB_PASSWORD | Key Vault secret ref | SQL Server password |
KC_HOSTNAME | Bicep param | auth.{env-domain} e.g. auth.microtec-test.com |
KC_HOSTNAME_STRICT | Static | false |
KC_PROXY_HEADERS | Static | xforwarded (AFD terminates TLS) |
KC_FEATURES | Static | persistent-user-sessions,token-exchange,admin-fine-grained-authz:v1 |
KEYCLOAK_ADMIN | Static | admin |
KEYCLOAK_ADMIN_PASSWORD | Key Vault secret ref | Admin console password |
JAVA_OPTS_APPEND | Static | -Xmx1500m |
SPI-Specific Variables
| Variable | Description |
|---|---|
KEYCLOAK_SEED_ENABLED | true — enables keycloak-seeding SPI |
KEYCLOAK_SEED_PATH | /opt/keycloak/seed |
ADMIN_DB_CONNECTION_STRING | JDBC URL for company-branch and policy mappers |
TWILIO_ACCOUNT_SID | Phone OTP: Twilio account |
TWILIO_AUTH_TOKEN | Phone OTP: Twilio auth token |
TWILIO_FROM_NUMBER | Phone OTP: sender number |
SENDGRID_API_KEY | Email OTP: SendGrid API key |
MAC_ENCRYPTION_KEY | Multi-account SPI encryption key (Base64, 256-bit) |
Per-Environment Hostname Reference
| Environment | KC_HOSTNAME |
|---|---|
| dev | auth.microtec-test.com |
| stage | auth.microtecstage.com |
| preprod | auth.microtec-preprod.com |
| uat | auth.microtec-uat.com |
| production | auth.onlinemicrotec.com.sa |
Database Setup
Keycloak uses a dedicated database on the shared SQL Server VM:
sql
-- Run on mic-backend-shared-sql-rg SQL Server
CREATE DATABASE [Microtec.SSO];
-- Uses the 'sa' account (KC_DB_USERNAME=sa) — no separate login required
USE [Microtec.SSO];
-- Keycloak auto-creates its schema on first startupKeycloak auto-creates its schema (100+ tables) on first startup. The sa account provides sufficient access for initial schema creation and ongoing operation.
Realm Import
Realms are provisioned by the keycloak-seeding SPI on container startup. The seed files (/opt/keycloak/seed/*.json) are baked into the custom image. This is an idempotent operation — existing realms are not overwritten.
See Seeding SPI for full details.
SPI JAR Deployment
SPI JARs are baked into the Docker image. There is no runtime JAR drop — updating a SPI requires rebuilding and redeploying the Keycloak image:
bash
# 1. Build new JAR (Maven)
cd KeycloakProviders
mvn clean package -pl keycloak-company-branch-mapper
# 2. Copy JAR to providers/ directory used by Dockerfile
cp keycloak-company-branch-mapper/target/keycloak-company-branch-mapper-*.jar \
docker/providers/
# 3. Build and push new Keycloak image
docker build -t micerpbe{env}acr.azurecr.io/keycloak:{new-tag} .
docker push micerpbe{env}acr.azurecr.io/keycloak:{new-tag}
# 4. Update container app image tag
az containerapp update \
--name keycloak \
--resource-group mic-erp-be-{env}-apps-public-rg \
--image micerpbe{env}acr.azurecr.io/keycloak:{new-tag}Zero-Downtime SPI Updates
Keycloak requires a restart to load new provider JARs. Schedule SPI updates during low-traffic windows. The Container App rolling update keeps one replica serving traffic while the new replica starts, but there is a brief period where the new SPI version may not be active on all replicas.
Health and Readiness
| Endpoint | Port | Purpose |
|---|---|---|
/health/live | 9000 | Liveness probe (JVM alive) |
/health/ready | 9000 | Readiness probe (DB connected, providers loaded) |
/health | 9000 | Full Keycloak health report |
/realms/microtec/.well-known/openid-configuration | 8080 | OIDC discovery endpoint |
The Container App is configured with:
- Liveness probe:
/health/liveon port 9000 — initial delay 60s, period 60s - Readiness probe:
/health/readyon port 9000 — initial delay 30s, period 15s
Admin Console Access
The Keycloak admin console is available at:
https://auth.{env-domain}/adminProduction Admin Console
The admin console is exposed on the same public URL in all environments. In production, access is restricted via Azure Front Door WAF rules — admin paths (/admin/*) are blocked except from Microtec office IP ranges. Do NOT disable this WAF rule.
Troubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Container fails to start (DB error) | Wrong KC_DB_URL or DB not created | Check JDBC URL; verify Microtec.SSO database exists on SQL Server |
| Login page shows generic Keycloak theme | Custom theme not loaded | Verify theme JARs/folders in image; check KC_SPI_THEME_* vars |
Realm not found on OIDC discovery | Seeding SPI failed | Check container logs for seeding errors; verify KEYCLOAK_SEED_ENABLED=true |
| 503 from AFD to Keycloak | Readiness probe failing | Check /health/ready; verify DB connectivity and all provider JARs loaded |
| Token missing custom claims | Protocol mapper JAR missing | Verify all provider JARs present in /opt/keycloak/providers/ |
Related Documentation
- Realm Configuration — Realm settings, client IDs, token lifetimes
- Seeding SPI — Automated realm provisioning
- Multi-Account SPI — MAC cookie authenticator
- Phone/Email OTP Authenticator — Second-factor SPI
- Company Branch Mapper — Tenant claims SPI
- ERP Policy Mapper — Permission claims SPI
- Container Apps — CAE architecture