Skip to content

PP Environment — Abu Dhabi Production (ai71-pp-auh1-prod-ask)

On-premises government cloud deployment
Cluster: RKE2 on bare-metal / private cloud, Abu Dhabi (AUH1)
Domain: *.ask.pp.gov.ae
Registry: registry.pp.gov.ae (Harbor, fully air-gapped)
Secrets backend: HashiCorp Vault (in-cluster) — not Azure Key Vault
ArgoCD branch: feat/pp-deployment (devops repo)


Why PP Is Different

The PP environment is a sovereign, air-gapped deployment for a government customer. Key differences from all Azure environments:

Concern Azure environments PP environment
Kubernetes AKS (managed) RKE2 (self-managed, bare-metal)
Container registry Azure Container Registry Harbor (registry.pp.gov.ae)
Secrets Azure Key Vault + ESO HashiCorp Vault + ESO
PostgreSQL Azure PostgreSQL Flexible Server Bitnami Helm chart (in-cluster)
Redis Azure Cache for Redis Bitnami Redis (in-cluster subchart)
Object storage Azure Blob S3-compatible (s3.pp.gov.ae)
LLM proxy AI71 Foundry (cloud) LiteLLM in-cluster (litellm.foundry.svc.cluster.local:4000)
Feature flags LaunchDarkly / Unleash (cloud) Offline mode with bootstrap JSON file
Daytona sandboxes Enabled Disabled (enable_code_execution: false)
TLS termination Azure App Gateway / ACR F5 load balancer at edge → ingress-nginx
Image source Built and pushed by CI to ACR Mirrored from ACR to Harbor via mirror-image.sh
Storage class Azure managed disks Longhorn
Extra service Voice Service (ask-voice-service)

DNS & Ingress Map

All traffic enters via F5 → ingress-nginx. TLS is terminated at the ingress using the ask-pp-gov-ae-cert TLS Secret (private CA).

Hostname Backend Service Path Namespace
ask.pp.gov.ae Frontend / ask
chat.ask.pp.gov.ae Frontend / ask
admin.ask.pp.gov.ae Frontend / ask
api.ask.pp.gov.ae Core Service /ask71/v2/svc/(.*)/ ask
api.ask.pp.gov.ae Core Service /(.*) (catch-all) ask
api.ask.pp.gov.ae Assistant Service /ask71/v2/astsvc(/|$)(.*)/ ask
api.ask.pp.gov.ae KMS /ask71/v2/kmsvc(/|$)(.*)/ ask
sso.ask.pp.gov.ae Zitadel (login) /ui/v2/login ask
sso.ask.pp.gov.ae Zitadel (gRPC) / (GRPC backend protocol) ask
hatchet.ask.pp.gov.ae Hatchet API /api hatchet
hatchet.ask.pp.gov.ae Hatchet Frontend / hatchet
litellm.ask.pp.gov.ae LiteLLM / foundry

Note: TLS cert Secret ask-pp-gov-ae-cert must include the full chain (leaf + intermediates). F5 terminates TLS at the edge; internal cluster traffic is plain HTTP. NODE_TLS_REJECT_UNAUTHORIZED=0 is set on the frontend pod because it calls the backend via public HTTPS hostnames signed by the private CA.


ArgoCD App-of-Apps Hierarchy

ai71-pp-auh1-prod-ask                    ← Root App
  repoURL: ask-devops  feat/pp-deployment
  path: environments/pp/auh1/prod/02-argocd-application/_root
  namespace: argocd
  ai71-pp-auh1-prod-ask.ask              ← App-of-Apps
    path: environments/pp/auh1/prod/02-argocd-application/ask
         ├─ ai71-pp-auh1-prod-ask.ask-core-service
         ├─ ai71-pp-auh1-prod-ask.ask-assistant-service
         ├─ ai71-pp-auh1-prod-ask.ask-frontend
         ├─ ai71-pp-auh1-prod-ask.ask-km-service
         ├─ ai71-pp-auh1-prod-ask.ask-voice-service
         ├─ ai71-pp-auh1-prod-ask.ask-hatchet          ← multi-source (chart: Harbor OCI, values: Git)
         ├─ ai71-pp-auh1-prod-ask.weaviate              ← multi-source
         └─ ai71-pp-auh1-prod-ask.postgresql            ← multi-source

All Application CRs have syncPolicy.automated: { prune: true, selfHeal: true }.


ArgoCD Applications — Summary Table

ArgoCD App Name Source Repo Branch Helm Values Namespace Pinned Image Tag
ask-core-service ask-core-service.git staging values-ai71-pp-auh1-prod-ask.yaml ask b4895f50
ask-assistant-service ask-assistant-service.git main values-ai71-pp-auh1-prod-ask.yaml ask d1fec387
ask-frontend ask-frontend.git feature/gitlab_manual_build values-ai71-pp-auh1-prod-ask.yaml ask staging-139ce0f1-pp-prod
ask-km-service ask-knowledge-management-service.git main values-ai71-pp-auh1-prod-ask.yaml + ai71-pp-auh1-prod-ask.toml ask 88ca403f
ask-voice-service ask-voice-service.git main values-ai71-pp-auh1-prod-ask.yaml ask 553d1ce0
ask-hatchet registry.pp.gov.ae/helm-charts chart 0.10.0 values-ai71-pp-auh1-prod.yaml (from devops Git) hatchet
weaviate registry.pp.gov.ae/helm-charts chart 17.7.0 values-ai71-pp-auh1-prod.yaml (from devops Git) weaviate
postgresql registry.pp.gov.ae/helm-charts chart 15.5.0 values-ai71-pp-auh1-prod.yaml (from devops Git) ask

Container Images — PP Registry

All application images are mirrored from ACR to Harbor before deployment.

Service ACR source Harbor target (registry.pp.gov.ae)
Core Service ai71uaenprodask71acr01.azurecr.io/core-service ask/ask-core-service
Core Service Bulk Worker ai71uaenprodask71acr01.azurecr.io/core-service-bulk-operations-worker ask/ask-core-service-bulk-operations-worker
Assistant Service ai71uaenprodask71acr01.azurecr.io/assistant-service ask/ask-assistant-service
Frontend ai71uaenprodask71acr01.azurecr.io/frontend ask/frontend-prod
KMS ai71uaenprodask71acr01.azurecr.io/ask-knowledge-management-service ask/ask-knowledge-management-service

Third-Party Images (mirrored to Harbor)

Image Harbor path Used by
python:3.12-slim-trixie — (base, build-time only) All Python services
node:22-alpine — (base, build-time only) Frontend
bitnami/postgresql:17.6.0-debian-12-r4 bitnamilegacy/postgresql:17.6.0-debian-12-r4 Hatchet subchart, shared PostgreSQL
bitnami/postgresql:18.1.0 bitnami/postgresql:18.1.0 KMS subchart
bitnami/redis:8.2.1-debian-12-r0 bitnamilegacy/redis:8.2.1-debian-12-r0 Assistant Service Redis subchart
bitnami/rabbitmq:4.1.3-debian-12-r1 bitnamilegacy/rabbitmq:4.1.3-debian-12-r1 Hatchet RabbitMQ subchart
library/postgres:16-alpine dockerhub/library/postgres:16-alpine Hatchet DB init
weaviate/weaviate:1.34.0 dockerhub/weaviate:1.34.0 Weaviate
library/alpine:3.20 dockerhub/library/alpine:3.20 Weaviate init container
hatchet/hatchet-api:v0.71.0 ghcr/hatchet/hatchet-api:v0.71.0 Hatchet API
hatchet/hatchet-engine:v0.71.0 ghcr/hatchet/hatchet-engine:v0.71.0 Hatchet Engine
hatchet/hatchet-frontend:v0.71.0 ghcr/hatchet/hatchet-frontend:v0.71.0 Hatchet UI
hatchet/hatchet-migrate:v0.71.0 ghcr/hatchet/hatchet-migrate:v0.71.0 Hatchet migration job
hatchet/hatchet-admin:v0.71.0 ghcr/hatchet/hatchet-admin:v0.71.0 Hatchet setup/seed jobs

Secrets Management — HashiCorp Vault

Setup

Vault is deployed in-cluster (namespace: hashicorp) and configured via Terraform (02-hashicorp-vault-configure/main.tf):

  • KV v2 engine mounted at kv/
  • Kubernetes auth backend enabled
  • ClusterSecretStore named vault-backend pointing to http://vault.hashicorp:8200
  • external-secrets-role bound to ServiceAccount external-secrets (namespace external-secrets)
  • ESO policy: read-only on kv/data/ask/prod/*

Vault KV Paths → Kubernetes Secrets

Vault KV Path K8s Secret Name Namespace Consumed By
kv/data/ask/prod/core-service/environment-secrets core-service-secret ask Core Service pod
kv/data/ask/prod/assistant-service/environment-secrets assistant-service-secret ask Assistant Service pod
kv/data/ask/prod/knowledge-management-service/environment-secrets knowledge-management-service-secret ask KMS pod
kv/data/ask/prod/postgres/environment-secrets postgres-secret ask Shared PostgreSQL
kv/data/ask/prod/zitadel/environment-secrets zitadel-secret ask Zitadel IAM
kv/data/ask/prod/weaviate/environment-secrets weaviate-secret weaviate Weaviate (API key)
kv/data/ask/prod/hatchet/environment-secrets hatchet-secret hatchet Hatchet (RabbitMQ password etc.)
kv/data/ask/prod/litellm/environment-variables litellm-secret foundry LiteLLM proxy

All ExternalSecret resources use refresh interval 1 minute.


Infrastructure Components

Shared PostgreSQL (Bitnami chart 15.5.0)

  • ArgoCD app: ai71-pp-auh1-prod-ask.postgresql
  • Namespace: ask
  • Architecture: Primary + 1 read replica
  • Storage: 220 Gi primary, 20 Gi replica (default storage class)
  • Node affinity: pinned to rke2-worker-node-11 (both primary and replica)
  • Secret: postgres-secret (key: postgres-password)
  • Tuning: max_connections=200, shared_buffers=4GB, effective_cache_size=12GB, WAL replication enabled

Weaviate (chart 17.7.0, app image 1.34.0)

  • ArgoCD app: ai71-pp-auh1-prod-ask.weaviate
  • Namespace: weaviate
  • Replicas: 3 (one per node: rke2-worker-node-07/08/09)
  • Storage: 512 Gi per replica
  • Auth: API key only (admin user), anonymous access disabled
  • Node affinity: role=weaviate (required, 1:1 pod-to-node via podAntiAffinity)
  • API key secret: weaviate-secret key AUTHENTICATION_APIKEY_ALLOWED_KEYS

Hatchet (chart 0.10.0, app image v0.71.0)

  • ArgoCD app: ai71-pp-auh1-prod-ask.ask-hatchet
  • Namespace: hatchet
  • URL: http://hatchet-api.hatchet.svc.cluster.local:8080 (internal); hatchet.ask.pp.gov.ae (external)
  • Includes subcharts: PostgreSQL (Bitnami), RabbitMQ (Bitnami)
  • PostgreSQL node: pinned to rke2-worker-node-10
  • RabbitMQ preset: medium (500m CPU, 1Gi RAM)
  • Engine memory limit: 8 Gi
  • Secret: hatchet-secret (RabbitMQ password, shared config override)

LiteLLM (in-cluster LLM proxy)

  • Namespace: foundry
  • Internal URL: http://litellm.foundry.svc.cluster.local:4000
  • External URL: litellm.ask.pp.gov.ae
  • Secret: litellm-secret (from Vault kv/data/ask/prod/litellm/environment-variables)
  • Serves OSS models (openai/gpt-oss-120b) for on-prem LLM inference

Zitadel IAM (v4.5.0, deployed as Core Service subchart)

  • Internal gRPC: http://core-service-zitadel.ask.svc.cluster.local:8080
  • External SSO: https://sso.ask.pp.gov.ae
  • Login UI: https://sso.ask.pp.gov.ae/ui/v2/login (Zitadel v4 login app)
  • Database: PostgreSQL zitadel DB on postgresql.ask.svc.cluster.local
  • Default org ID: 357511184963905565
  • TLS: Disabled inside cluster (TLS handled by F5/ingress); ExternalSecure: true for external URL

Node Topology

Pods are scheduled to dedicated node pools using nodeSelector + tolerations:

Node Role nodeSelector Workloads
ask node.kubernetes.io/role: ask All ASK application pods (core, assistant, frontend, kms)
postgres role: postgres Shared PostgreSQL (node-11), Hatchet PostgreSQL (node-10)
weaviate role: weaviate Weaviate pods (nodes 7, 8, 9)

Per-Service PP Configuration

Core Service

Config PP Value
app.env ai71-pp-auh1-prod-ask
database.host postgresql.ask.svc.cluster.local
database.name core-service
database.user core-service
iam_service.base_url http://core-service-zitadel.ask.svc.cluster.local:8080
iam_service.public_base_url https://sso.ask.pp.gov.ae
iam_service.default_org_id 357511184963905565
foundry.base_url http://litellm.foundry.svc.cluster.local:4000
storage.type azure (using Azure Blob CDN for static assets only)
storage.azure.account_name ai71uaensask71sa03
storage.cdn_base_url https://cdn.ask.stg.ai71services.ai
redis.host assistant-service-redis-master.ask.svc.cluster.local
redis.ssl true / cluster_mode: true
feature_flags.billing_enabled false
feature_flags.public_signup_enabled false
public.core_services_base_url https://api.ask.pp.gov.ae/ask71/v2/svc
knowledge_management_service.base_url http://knowledge-management-service.ask.svc.cluster.local
Workers enabled bulkOperationsWorker (3 replicas); billing/cron/job workers disabled
image.repository registry.pp.gov.ae/ask/ask-core-service

Assistant Service

Config PP Value
app.env ai71-pp-auh1-prod-ask
app.base_url http://api.ask.pp.gov.ae
app.fastapi_root_path /ask71/v2/astsvc
core_service.url http://core-service.ask.svc.cluster.local/api/v1
database.host postgresql.ask.svc.cluster.local
database.user assistant-service
foundry.endpoint http://litellm.foundry.svc.cluster.local:4000/v1
foundry.reranker.endpoint http://litellm.foundry.svc.cluster.local:4000/v1/rerank
storage.cdn_base_url https://cdn.ask.pp.gov.ae/static
kms.base_url http://knowledge-management-service.ask.svc.cluster.local
hatchet.client_tls_strategy none
hatchet.generic_worker_slots 5
redis.host assistant-service-redis-master.ask.svc.cluster.local
daytona.enable_code_execution false
tool_approval.flow_enabled false
feature_flags.mode offline (bootstrap: ./config/feature-flags/pp-prod.json)
assistants.default_public_assistant_name mujeeb
assistants.frontend_url https://ask.pp.gov.ae/
tooling.data_analysis.*_model openai/gpt-oss-120b (OSS on-prem model)
image.repository registry.pp.gov.ae/ask/ask-assistant-service
Redis subchart image registry.pp.gov.ae/bitnamilegacy/redis:8.2.1-debian-12-r0
postDeployJob.enabled false

Frontend

Config PP Value
image.repository registry.pp.gov.ae/ask/frontend-prod
replicaCount 1 (autoscaling: min 3, max 100, CPU target 80%)
NODE_TLS_REJECT_UNAUTHORIZED 0 (private CA cert workaround)
Ingress hosts ask.pp.gov.ae, chat.ask.pp.gov.ae, admin.ask.pp.gov.ae
TLS secret ask-pp-gov-ae-cert
Liveness/readiness /api/health, initial delay 60s

Knowledge Management Service (KMS)

Config PP Value
image.repository registry.pp.gov.ae/ask/ask-knowledge-management-service
core_service.services_base_url http://core-service.ask.svc.cluster.local
database.host Dynamic: {{ .Release.Name }}-postgresql-primary
database.name knowledge_management
database.user kms_user
database.pool_size 200
document_understanding.di_resource_name azure-document-intelligence-pp-prod
document_understanding.foundry_endpoint http://litellm.foundry.svc.cluster.local/v1
organization.vlm_model_name Qwen/Qwen3.5-9B
storage.type s3 (S3-compatible: s3.pp.gov.ae)
storage.s3.bucket_name ask-knowledge-management
storage.s3.endpoint_url https://s3.pp.gov.ae/
storage.s3.region us-east-1
storage.s3.verify_ssl false
vector_db.http_host weaviate.weaviate.svc.cluster.local
vector_db.grpc_host weaviate-grpc.weaviate.svc.cluster.local
S3 CA bundle Mounted from Secret s3-ca-bundle/config/s3/s3-cert.pem
PostgreSQL subchart enabled — Bitnami 18.1.0 with replication, Longhorn 300 Gi
ingestionAutoscaling.minReplicas 5

PP Secrets Required in Vault

Below is the combined list of secrets that must be populated in HashiCorp Vault before deploying to PP.

kv/data/ask/prod/core-service/environment-secrets

Key Description
DATABASE__PASSWORD PostgreSQL password for core-service user
SECURITY__API_KEY_SALT API key hashing salt
SECURITY__MASTER_ENCRYPTION_KEY Master encryption key
IAM_SERVICE__PAT Zitadel machine account PAT
NOTIFICATIONS__MAILCHIMP_API_KEY Mailchimp API key
STORAGE__ACCOUNT_KEY Azure Blob account key (CDN static assets)
STORAGE__SAS_TOKEN Azure Blob SAS token
HATCHET__CLIENT_TOKEN Hatchet client token
REDIS__PASSWORD Redis AUTH password
FOUNDRY__API_KEY LiteLLM API key
APP__CORE_SERVICES_MACHINE_TOKEN Machine token for internal job → API calls

kv/data/ask/prod/assistant-service/environment-secrets

Key Description
DATABASE__PASSWORD PostgreSQL password for assistant-service user
HATCHET__CLIENT_TOKEN Hatchet client token
CORE_SERVICE__JWT_SECRET JWT secret for Core Service calls
CORE_SERVICE_ENCRYPTION_KEY Encryption key for Core Service tokens
AI71_FOUNDRY_KEY LiteLLM / Foundry API key
AI71_AUTH_STATE_SECRET OAuth state encryption secret
REDIS_PASSWORD Redis AUTH password (matches core-service)

kv/data/ask/prod/knowledge-management-service/environment-secrets

Key Description
DATABASE__PASSWORD PostgreSQL password for kms_user
APP__MASTER_ENCRYPTION_KEY Master encryption key
CORE_SERVICE__JWT_SECRET JWT secret for inter-service auth
DOCUMENT_UNDERSTANDING__DI_SUBSCRIPTION_KEY Azure Document Intelligence key
DOCUMENT_UNDERSTANDING__FOUNDRY_KEY LiteLLM / Foundry key for DU
DOCUMENT_UNDERSTANDING__KEYWORD_EXTRACTION__NER_TOKEN NER model token
STORAGE__S3__ACCESS_KEY_ID S3 access key (s3.pp.gov.ae)
STORAGE__S3__SECRET_ACCESS_KEY S3 secret key
VECTOR_DB__API_KEY Weaviate API key

kv/data/ask/prod/postgres/environment-secrets

Key Description
postgres-password Shared PostgreSQL admin/user password

kv/data/ask/prod/zitadel/environment-secrets

Key Description
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD Zitadel DB user password
masterkey Zitadel master key (must be in zitadel-secret)

kv/data/ask/prod/weaviate/environment-secrets

Key Description
AUTHENTICATION_APIKEY_ALLOWED_KEYS Weaviate API key (maps to admin user)

kv/data/ask/prod/hatchet/environment-secrets

Key Description
RABBITMQ_PASSWORD RabbitMQ auth password
(other Hatchet shared config keys) As required by hatchet-shared-config secret

kv/data/ask/prod/litellm/environment-variables

Key Description
(LiteLLM config keys) API keys for OSS model endpoints, master key, etc.

Image Mirroring

Before deploying a new image version, mirror it from ACR to Harbor:

# Script: environments/pp/auh1/prod/03-scripts/mirror-image.sh
# Source: ai71uaenprodask71acr01.azurecr.io
# Target: registry.pp.gov.ae/ask

./mirror-image.sh [--dry-run] [--parallel]

Service mappings (configured in script):

assistant-service                      → ask/ask-assistant-service
core-service                           → ask/ask-core-service
core-service-bulk-operations-worker    → ask/ask-core-service-bulk-operations-worker

The script retries up to 3 times per image and writes structured logs to ./logs/mirror-<timestamp>.log.