Skip to content

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:

  1. The 7 SPI JARs (providers)
  2. Custom login themes (RTL + BO)
  3. 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:

EnvironmentTag PatternExample
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)

VariableSourceDescription
KC_DBStaticmssql
KC_DB_URLBicep paramJDBC URL: jdbc:sqlserver://{host};databaseName=Microtec.SSO
KC_DB_USERNAMEStaticsa
KC_DB_PASSWORDKey Vault secret refSQL Server password
KC_HOSTNAMEBicep paramauth.{env-domain} e.g. auth.microtec-test.com
KC_HOSTNAME_STRICTStaticfalse
KC_PROXY_HEADERSStaticxforwarded (AFD terminates TLS)
KC_FEATURESStaticpersistent-user-sessions,token-exchange,admin-fine-grained-authz:v1
KEYCLOAK_ADMINStaticadmin
KEYCLOAK_ADMIN_PASSWORDKey Vault secret refAdmin console password
JAVA_OPTS_APPENDStatic-Xmx1500m

SPI-Specific Variables

VariableDescription
KEYCLOAK_SEED_ENABLEDtrue — enables keycloak-seeding SPI
KEYCLOAK_SEED_PATH/opt/keycloak/seed
ADMIN_DB_CONNECTION_STRINGJDBC URL for company-branch and policy mappers
TWILIO_ACCOUNT_SIDPhone OTP: Twilio account
TWILIO_AUTH_TOKENPhone OTP: Twilio auth token
TWILIO_FROM_NUMBERPhone OTP: sender number
SENDGRID_API_KEYEmail OTP: SendGrid API key
MAC_ENCRYPTION_KEYMulti-account SPI encryption key (Base64, 256-bit)

Per-Environment Hostname Reference

EnvironmentKC_HOSTNAME
devauth.microtec-test.com
stageauth.microtecstage.com
preprodauth.microtec-preprod.com
uatauth.microtec-uat.com
productionauth.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 startup

Keycloak 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

EndpointPortPurpose
/health/live9000Liveness probe (JVM alive)
/health/ready9000Readiness probe (DB connected, providers loaded)
/health9000Full Keycloak health report
/realms/microtec/.well-known/openid-configuration8080OIDC discovery endpoint

The Container App is configured with:

  • Liveness probe: /health/live on port 9000 — initial delay 60s, period 60s
  • Readiness probe: /health/ready on port 9000 — initial delay 30s, period 15s

Admin Console Access

The Keycloak admin console is available at:

https://auth.{env-domain}/admin

Production 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

SymptomLikely CauseResolution
Container fails to start (DB error)Wrong KC_DB_URL or DB not createdCheck JDBC URL; verify Microtec.SSO database exists on SQL Server
Login page shows generic Keycloak themeCustom theme not loadedVerify theme JARs/folders in image; check KC_SPI_THEME_* vars
Realm not found on OIDC discoverySeeding SPI failedCheck container logs for seeding errors; verify KEYCLOAK_SEED_ENABLED=true
503 from AFD to KeycloakReadiness probe failingCheck /health/ready; verify DB connectivity and all provider JARs loaded
Token missing custom claimsProtocol mapper JAR missingVerify all provider JARs present in /opt/keycloak/providers/

Internal Documentation — Microtec Platform Team