Regional Guide13 min readApril 16, 2026

Keycloak Deployment in UAE: AWS Bahrain & Azure UAE Regions

A practical guide to deploying Keycloak in the UAE using AWS Bahrain (me-south-1) or Azure UAE North, meeting UAE PDPL data residency requirements and enterprise performance expectations.

KT

KeycloakPro Team

KeycloakPro Team

Why UAE Deployment Matters for Identity Infrastructure

When a user in Dubai logs into your application, the authentication request should not travel to a data center in Ireland or Virginia. Latency aside, the more significant issue is legal: the UAE's Federal Decree-Law No. 45 of 2021 on Personal Data Protection (PDPL) and sectoral regulations from CBUAE, DIFC, and ADGM all create pressure — and in some cases requirements — for authentication data to remain within UAE jurisdiction.

For companies deploying Keycloak in the UAE, two cloud regions are available: AWS me-south-1 (Bahrain) and Azure UAE North (Dubai). Both are within the GCC geographic zone and satisfy UAE enterprise data residency requirements in most procurement contexts. This guide covers deploying a production Keycloak cluster in each.


Choosing Your Cloud Region

AWS Bahrain (me-south-1)

AWS launched me-south-1 in Bahrain in 2019 — the first AWS region in the Middle East. As of 2026, it offers:

  • Three Availability Zones (AZ)
  • Full suite: EC2, RDS, ElastiCache, EKS, ALB, CloudFront, WAF, Secrets Manager, CloudWatch
  • Latency from Dubai: ~8–12ms; from Riyadh: ~15–20ms; from Mumbai: ~80ms

The Bahrain region is the default choice for companies serving the UAE, Saudi Arabia, and the broader GCC without a hard requirement for UAE-specific data residency.

Compliance note: Bahrain sits outside the UAE. For companies operating under DIFC, ADGM, or CBUAE regulations that specify UAE data residency (not merely GCC), verify with your legal counsel whether me-south-1 satisfies your obligation. Most commercial contracts specify "GCC region" rather than "UAE only" — Bahrain satisfies those.

Azure UAE North (uaenorth)

Azure UAE North (Dubai) launched in 2019 and is co-located at Dubai's Jebel Ali data centers. It offers:

  • Two data center facilities in Dubai (paired with UAE Central in Abu Dhabi)
  • Services: Azure VMs, AKS, Azure Database for PostgreSQL, Azure Cache for Redis, Azure Application Gateway, Azure CDN, Key Vault, Monitor
  • Latency from Dubai: ~2–5ms (within-city); from Abu Dhabi: ~10ms

Azure UAE North is the preferred choice for:

  • DIFC and ADGM regulated entities that require UAE-resident data
  • Companies standardized on Microsoft Azure
  • UAE government digital service providers
  • Healthcare and financial services companies with explicit UAE-resident data clauses in their compliance framework

Choosing Between Them

CriterionAWS Bahrain (me-south-1)Azure UAE North
Latency (Dubai users)~8–12ms~2–5ms
AZ count3 (higher HA redundancy)2
Managed KubernetesEKSAKS
Managed PostgreSQLRDS (Multi-AZ available)Azure Database for PostgreSQL
UAE-specific data residencyNo — GCC regionYes — Dubai
CDN edge in UAECloudFront (uses UAE PoPs)Azure CDN / Front Door
Existing Microsoft licensingN/AAzure Hybrid Benefit applicable

If your team uses AWS and your contracts say "GCC region," use Bahrain. If you need Dubai-specific residency or are Azure-first, use UAE North.


Architecture Overview

A production Keycloak deployment in the UAE follows the same general pattern regardless of cloud:

[Users in UAE/GCC]
        │
        ▼
[CDN / WAF Layer]          ← CloudFront + WAF Shield / Azure Front Door + WAF
        │
        ▼
[Load Balancer]            ← AWS ALB / Azure Application Gateway
        │
        ▼
[Keycloak Cluster]         ← 2–3 nodes across AZs, Infinispan cache sync
        │
        ▼
[PostgreSQL (Multi-AZ)]    ← RDS PostgreSQL / Azure Database for PostgreSQL
        │
        ▼
[Session Cache]            ← ElastiCache Redis / Azure Cache for Redis

All components must be in the same region. Cross-region replication of authentication data triggers data transfer obligations that complicate compliance.


Option A: AWS Bahrain Deployment

Infrastructure Setup

1. VPC and Networking

Create a dedicated VPC for the identity stack:

# Create VPC
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --region me-south-1 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=keycloak-vpc}]'

# Create private subnets in each AZ (me-south-1a, 1b, 1c)
# Keycloak nodes and database live in private subnets
# Load balancer lives in public subnets

2. RDS PostgreSQL in me-south-1

aws rds create-db-instance \
  --db-instance-identifier keycloak-prod \
  --db-instance-class db.t3.medium \
  --engine postgres \
  --engine-version 16.1 \
  --master-username keycloak \
  --master-user-password "${DB_PASSWORD}" \
  --db-name keycloak \
  --vpc-security-group-ids sg-XXXXXXXX \
  --db-subnet-group-name keycloak-subnet-group \
  --multi-az \
  --storage-type gp3 \
  --allocated-storage 100 \
  --storage-encrypted \
  --region me-south-1

Multi-AZ ensures RDS automatically fails over within Bahrain without data leaving the region.

3. ElastiCache Redis

Keycloak 26+ uses an Infinispan-based distributed cache. For production deployments with external session storage:

aws elasticache create-replication-group \
  --replication-group-id keycloak-sessions \
  --description "Keycloak session cache" \
  --engine redis \
  --engine-version 7.1 \
  --cache-node-type cache.t3.medium \
  --num-cache-clusters 2 \
  --security-group-ids sg-XXXXXXXX \
  --subnet-group-name keycloak-cache-subnet \
  --at-rest-encryption-enabled \
  --transit-encryption-enabled \
  --region me-south-1

4. Application Load Balancer + Certificate

Request an ACM certificate in me-south-1 for your Keycloak domain (e.g., auth.yourcompany.ae or login.yourcompany.com):

aws acm request-certificate \
  --domain-name auth.yourcompany.ae \
  --validation-method DNS \
  --region me-south-1

Attach the certificate to an HTTPS listener on the ALB.

5. Keycloak EC2 Auto Scaling Group

Launch Keycloak on EC2 (or ECS/EKS — same configuration). Minimum 2 instances across 2 AZs. Use a launch template:

# User data for Keycloak startup
#!/bin/bash
export KC_DB=postgres
export KC_DB_URL="jdbc:postgresql://${RDS_ENDPOINT}:5432/keycloak"
export KC_DB_USERNAME=keycloak
export KC_DB_PASSWORD=$(aws secretsmanager get-secret-value \
  --secret-id keycloak/db-password \
  --query SecretString \
  --output text \
  --region me-south-1)
export KC_HOSTNAME=auth.yourcompany.ae
export KC_HTTP_ENABLED=true
export KC_HTTP_PORT=8080
export KC_PROXY=edge
export KC_CACHE=ispn
export KC_CACHE_STACK=ec2  # Uses JGroups EC2 discovery

/opt/keycloak/bin/kc.sh start --optimized \
  --spi-connections-jpa-legacy-migration-strategy=update

KC_CACHE_STACK=ec2 enables JGroups EC2 discovery — Keycloak cluster nodes find each other automatically using the EC2 API (no static IP configuration required).

Required IAM permissions for the EC2 role:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstances",
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "*"
    }
  ]
}

6. CloudFront Distribution (UAE PoPs)

CloudFront has PoPs in Dubai (DXB) and Bahrain (BAH). Configure CloudFront in front of the ALB:

{
  "Origins": [{
    "DomainName": "keycloak-alb.me-south-1.elb.amazonaws.com",
    "Id": "keycloak-alb",
    "CustomOriginConfig": {
      "HTTPSPort": 443,
      "OriginProtocolPolicy": "https-only"
    }
  }],
  "DefaultCacheBehavior": {
    "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",  // CachingDisabled
    "OriginRequestPolicyId": "216adef6-5eab-4815-9e16-d6b87a06e0c8",  // AllViewer
    "ViewerProtocolPolicy": "redirect-to-https"
  }
}

Use the CachingDisabled managed policy — authentication endpoints must not be cached. CloudFront is used here for DDoS protection (Shield Standard) and UAE/GCC edge presence, not for caching.


Option B: Azure UAE North Deployment

Infrastructure via Terraform

# providers.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.90"
    }
  }
}

provider "azurerm" {
  features {}
}

# Resource group in UAE North
resource "azurerm_resource_group" "keycloak" {
  name     = "keycloak-prod-rg"
  location = "uaenorth"
}

Virtual Network and Subnets

resource "azurerm_virtual_network" "keycloak" {
  name                = "keycloak-vnet"
  location            = azurerm_resource_group.keycloak.location
  resource_group_name = azurerm_resource_group.keycloak.name
  address_space       = ["10.0.0.0/16"]
}

resource "azurerm_subnet" "private" {
  name                 = "keycloak-private"
  resource_group_name  = azurerm_resource_group.keycloak.name
  virtual_network_name = azurerm_virtual_network.keycloak.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_subnet" "appgw" {
  name                 = "appgw-subnet"
  resource_group_name  = azurerm_resource_group.keycloak.name
  virtual_network_name = azurerm_virtual_network.keycloak.name
  address_prefixes     = ["10.0.2.0/24"]
}

Azure Database for PostgreSQL — Flexible Server

resource "azurerm_postgresql_flexible_server" "keycloak" {
  name                   = "keycloak-db-prod"
  resource_group_name    = azurerm_resource_group.keycloak.name
  location               = azurerm_resource_group.keycloak.location
  version                = "16"
  administrator_login    = "keycloakadmin"
  administrator_password = var.db_password
  storage_mb             = 65536
  sku_name               = "GP_Standard_D2s_v3"

  high_availability {
    mode = "ZoneRedundant"  # Requires UAE North to have zone support
  }

  backup_retention_days        = 35
  geo_redundant_backup_enabled = false  # Keep data in UAE — no geo-backup to other regions
}

Note: geo_redundant_backup_enabled = false is deliberate — enabling geo-redundant backup copies data to paired Azure regions, which may be outside the UAE. For UAE data residency compliance, keep this disabled and manage backups within UAE North.

Azure Cache for Redis

resource "azurerm_redis_cache" "keycloak" {
  name                = "keycloak-sessions"
  location            = azurerm_resource_group.keycloak.location
  resource_group_name = azurerm_resource_group.keycloak.name
  capacity            = 1
  family              = "C"
  sku_name            = "Standard"
  enable_non_ssl_port = false
  minimum_tls_version = "1.2"
}

Azure Kubernetes Service (AKS) for Keycloak

resource "azurerm_kubernetes_cluster" "keycloak" {
  name                = "keycloak-aks"
  location            = azurerm_resource_group.keycloak.location
  resource_group_name = azurerm_resource_group.keycloak.name
  dns_prefix          = "keycloak-uae"

  default_node_pool {
    name           = "default"
    node_count     = 3
    vm_size        = "Standard_D4s_v3"
    vnet_subnet_id = azurerm_subnet.private.id
    zones          = ["1", "2"]  # Spread across AZs in UAE North
  }

  identity {
    type = "SystemAssigned"
  }
}

Keycloak Helm Values for Azure

# keycloak-values-azure.yaml
replicaCount: 3

image:
  repository: quay.io/keycloak/keycloak
  tag: "26.1"

extraEnv:
  - name: KC_DB
    value: postgres
  - name: KC_DB_URL
    value: "jdbc:postgresql://keycloak-db-prod.postgres.database.azure.com:5432/keycloak"
  - name: KC_HOSTNAME
    value: auth.yourcompany.ae
  - name: KC_HTTP_ENABLED
    value: "true"
  - name: KC_PROXY
    value: edge
  - name: KC_CACHE
    value: ispn
  - name: KC_CACHE_STACK
    value: kubernetes  # JGroups Kubernetes discovery
  - name: JAVA_OPTS_APPEND
    value: "-Xms512m -Xmx1536m -XX:MetaspaceSize=96M"

extraEnvFrom:
  - secretRef:
      name: keycloak-db-secret

service:
  type: ClusterIP

ingress:
  enabled: true
  className: azure-application-gateway
  annotations:
    appgw.ingress.kubernetes.io/ssl-redirect: "true"
  hosts:
    - host: auth.yourcompany.ae
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: keycloak-tls
      hosts:
        - auth.yourcompany.ae

podDisruptionBudget:
  enabled: true
  minAvailable: 2

resources:
  requests:
    cpu: 500m
    memory: 1Gi
  limits:
    cpu: 2000m
    memory: 2Gi

KC_CACHE_STACK=kubernetes enables JGroups DNS-based Kubernetes discovery for cluster formation — nodes find each other via the Kubernetes headless service.


SSL/TLS Configuration

All production Keycloak deployments in the UAE must terminate TLS at the load balancer, not at Keycloak directly. The KC_PROXY=edge setting tells Keycloak it is behind a TLS-terminating proxy.

Security headers to configure at the proxy layer:

# For nginx-based configurations
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=()" always;

Minimum TLS version: TLS 1.2. For high-security environments (DIFC, ADGM regulated), enforce TLS 1.3 only.


UAE-Specific Configuration

Hostname and Locale

UAE enterprise users expect Arabic localization. Keycloak supports RTL themes:

# Install Arabic theme (community or custom)
# In keycloak/themes/arabic-rtl/login/messages/messages_ar.properties
loginTitle=تسجيل الدخول
usernameOrEmail=اسم المستخدم أو البريد الإلكتروني
password=كلمة المرور
doLogIn=تسجيل الدخول

Set the default locale at the realm level:

{
  "internationalizationEnabled": true,
  "supportedLocales": ["en", "ar"],
  "defaultLocale": "en"
}

UAE National ID Integration

For deployments that integrate UAE Pass (the UAE national digital identity), Keycloak acts as the Service Provider (SP) in an OIDC federation with UAE Pass as the IdP. Configure an identity provider in Keycloak using UAE Pass's OIDC discovery endpoint.

Time Zone

UAE is UTC+4 (Gulf Standard Time, no DST). Configure your PostgreSQL connection and application logging to use Asia/Dubai:

# In PostgreSQL configuration
PGTZ: "Asia/Dubai"

# In Keycloak JVM options
-Duser.timezone=Asia/Dubai

This ensures audit log timestamps are in UAE local time — important when responding to PDPL audit requests.


PDPL Compliance Configuration

Data Residency Verification

After deployment, verify that no authentication data leaves the region:

For AWS Bahrain: Enable CloudTrail and VPC Flow Logs. Review for any traffic to non-me-south-1 endpoints. Secrets Manager, RDS, and ElastiCache calls should all resolve to *.me-south-1.* endpoints.

For Azure UAE North: Enable Azure Monitor and review Azure Diagnostics for cross-region data transfer. Ensure geo-redundant backup is disabled on all storage resources.

UAE PDPL Article 10 requires explicit, informed consent for personal data processing. Configure Keycloak consent screens:

{
  "attributes": {
    "clientConsentRequired": "true"
  },
  "consentText": "By logging in, you consent to processing your personal data as described in our Privacy Policy, in accordance with UAE Federal Decree-Law No. 45 of 2021.",
  "defaultClientScopes": ["openid", "profile"],
  "optionalClientScopes": ["email", "phone"]
}

Audit Logging for PDPL Compliance

Enable Keycloak's event logging and set 90-day minimum retention (UAE PDPL Article 14 requires organizations to retain records to demonstrate compliance):

{
  "eventsEnabled": true,
  "enabledEventTypes": [
    "LOGIN", "LOGIN_ERROR", "LOGOUT",
    "REGISTER", "REGISTER_ERROR",
    "RESET_PASSWORD", "RESET_PASSWORD_ERROR",
    "UPDATE_CONSENT", "REVOKE_GRANT",
    "DELETE_ACCOUNT"
  ],
  "adminEventsEnabled": true,
  "adminEventsDetailsEnabled": true,
  "eventsExpiration": 7776000
}

Ship events to Azure Monitor Logs or AWS CloudWatch Logs for long-term retention beyond Keycloak's internal event store.


Performance Expectations

For a 2-node Keycloak cluster in either UAE region:

MetricExpected Value
Authentication request latency (Dubai)50–120ms (end-to-end, including network)
Keycloak process latency (auth endpoint)20–40ms
Token validation latency (JWT introspection)5–15ms
Cluster failover time (node failure)30–60 seconds
RDS failover time (Multi-AZ)60–120 seconds
Sessions supported (2-node, 4GB RAM each)~50,000 concurrent

For 200,000+ concurrent sessions, scale to 4+ nodes and consider an external Infinispan cluster or Redis for session storage.


Operational Considerations

Key Rotation

Rotate Keycloak realm signing keys annually (PDPL Article 16 — security measures for personal data protection). In the Keycloak admin console: Realm Settings → Keys → Add keystore (RSA-OAEP, 2048-bit). Set a 1-year expiry on active keys. Keycloak handles key rotation without invalidating existing tokens within their validity window.

Backup and Recovery

AWS: RDS automated backups (retain 35 days). Export realm configuration weekly via Admin API:

aws s3 cp realm-export.json s3://keycloak-backups-${ACCOUNT_ID}/realm-exports/$(date +%Y%m%d)/

Azure: Azure Database for PostgreSQL backup (retain 35 days). Store realm exports in Azure Blob Storage with immutable storage policies.

Monitoring

Set up alerts for:

  • Login error rate > 5% over 5 minutes (possible credential stuffing)
  • Authentication latency > 500ms p99
  • Database connection pool utilization > 80%
  • JVM heap utilization > 85%

Getting Deployed

A production Keycloak deployment in the UAE — HA cluster, PostgreSQL, TLS, audit logging, PDPL consent configuration, and the compliance documentation package — typically takes 2–3 weeks from kickoff to go-live.

KeycloakPro deploys on your AWS Bahrain or Azure UAE North account. You retain ownership of all infrastructure; we provide the deployment, configuration, and ongoing managed operations.

Book a UAE deployment assessment →

Need Help With Keycloak?

Our team specializes in production-grade Keycloak deployments. Get a free 30-minute strategy consultation.

Book a Free Strategy Call