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.
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
| Criterion | AWS Bahrain (me-south-1) | Azure UAE North |
|---|---|---|
| Latency (Dubai users) | ~8–12ms | ~2–5ms |
| AZ count | 3 (higher HA redundancy) | 2 |
| Managed Kubernetes | EKS | AKS |
| Managed PostgreSQL | RDS (Multi-AZ available) | Azure Database for PostgreSQL |
| UAE-specific data residency | No — GCC region | Yes — Dubai |
| CDN edge in UAE | CloudFront (uses UAE PoPs) | Azure CDN / Front Door |
| Existing Microsoft licensing | N/A | Azure 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.
Consent Management for UAE PDPL
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:
| Metric | Expected 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.
Need Help With Keycloak?
Our team specializes in production-grade Keycloak deployments. Get a free 30-minute strategy consultation.
Book a Free Strategy Call