Skip to main content

Azure AKS

Deploy the Watchlight AI Agent Runtime Governance control plane (Beacon) on Azure Kubernetes Service.

Prerequisites

RequirementDetails
AKS clusterKubernetes 1.27+
Azure CLIv2.x, authenticated with appropriate subscription
kubectlConfigured for your AKS cluster
Helmv3.12+
Application Gateway Ingress Controller (AGIC)Installed as an AKS add-on or via Helm
GHCR accessImage pull secret for ghcr.io/watchlight-ai-beacon

Required Azure RBAC roles

The deploying principal needs:

  • Contributor on the resource group (or scoped to AKS, PostgreSQL, Application Gateway)
  • Key Vault Secrets User (if using Azure Key Vault for secrets)
  • Network Contributor (for Application Gateway integration)

Infrastructure Setup

1. Create a resource group

az group create \
--name watchlight-beacon-rg \
--location eastus

2. Create the AKS cluster with AGIC

az aks create \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--node-count 3 \
--node-vm-size Standard_D4s_v5 \
--enable-managed-identity \
--enable-addons ingress-appgw \
--appgw-name beacon-appgw \
--appgw-subnet-cidr "10.225.0.0/16" \
--network-plugin azure \
--generate-ssh-keys

az aks get-credentials \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon

3. Provision Azure Database for PostgreSQL (Flexible Server)

az postgres flexible-server create \
--resource-group watchlight-beacon-rg \
--name beacon-db \
--location eastus \
--sku-name Standard_D2ds_v4 \
--tier GeneralPurpose \
--version 16 \
--storage-size 64 \
--admin-user beacon \
--admin-password "$(openssl rand -base64 24)" \
--high-availability ZoneRedundant \
--backup-retention 7

az postgres flexible-server db create \
--resource-group watchlight-beacon-rg \
--server-name beacon-db \
--database-name beacon

Allow access from the AKS cluster's VNet:

# Get the AKS VNet
AKS_VNET=$(az aks show \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--query 'agentPoolProfiles[0].vnetSubnetId' -o tsv | sed 's|/subnets/.*||')

az postgres flexible-server vnet-rule create \
--resource-group watchlight-beacon-rg \
--server-name beacon-db \
--vnet "$AKS_VNET" \
--subnet aks-subnet \
--rule-name allow-aks

4. Create the GHCR image pull secret

kubectl create namespace watchlight

kubectl create secret docker-registry ghcr-credentials \
-n watchlight \
--docker-server=ghcr.io \
--docker-username=YOUR_GITHUB_USERNAME \
--docker-password=YOUR_GITHUB_PAT

5. Create the database connection secret

kubectl create secret generic beacon-db-credentials \
-n watchlight \
--from-literal=DATABASE_URL="postgres://beacon:PASSWORD@beacon-db.postgres.database.azure.com:5432/beacon?sslmode=require"

6. (Optional) Azure Key Vault for secrets management

Instead of storing secrets directly in Kubernetes, use the Azure Key Vault Provider for Secrets Store CSI Driver:

az aks enable-addons \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--addons azure-keyvault-secrets-provider

az keyvault create \
--resource-group watchlight-beacon-rg \
--name beacon-vault \
--location eastus

az keyvault secret set \
--vault-name beacon-vault \
--name beacon-db-url \
--value "postgres://beacon:PASSWORD@beacon-db.postgres.database.azure.com:5432/beacon?sslmode=require"

Then create a SecretProviderClass to sync Key Vault secrets into Kubernetes:

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: beacon-secrets
namespace: watchlight
spec:
provider: azure
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "<MANAGED_IDENTITY_CLIENT_ID>"
keyvaultName: beacon-vault
objects: |
array:
- |
objectName: beacon-db-url
objectType: secret
tenantId: "<TENANT_ID>"
secretObjects:
- secretName: beacon-db-credentials
type: Opaque
data:
- objectName: beacon-db-url
key: DATABASE_URL

Helm Installation

Review the values file

The Azure-specific values file is at deploy/helm/watchlight-beacon/values-azure.yaml. Key settings:

global:
imageRegistry: ghcr.io/watchlight-ai-beacon
imagePullSecrets:
- name: ghcr-credentials
storageClass: managed-premium

ingress:
className: azure-application-gateway
annotations:
kubernetes.io/ingress.class: azure/application-gateway
appgw.ingress.kubernetes.io/ssl-redirect: "true"
# For Azure-managed certificates:
# appgw.ingress.kubernetes.io/appgw-ssl-certificate: beacon-cert

Before installing, update the values file with:

  1. Your TLS certificate name (uncomment appgw.ingress.kubernetes.io/appgw-ssl-certificate or configure cert-manager)
  2. Your domain name under wl-registry.ingress.hosts[].host and wl-registry-frontend.ingress.hosts[].host
  3. Your PostgreSQL connection string under global.externalDatabase.url (and set postgresql.enabled: false)

Configure TLS on Application Gateway

Upload your TLS certificate to Application Gateway:

az network application-gateway ssl-cert create \
--resource-group MC_watchlight-beacon-rg_watchlight-beacon_eastus \
--gateway-name beacon-appgw \
--name beacon-cert \
--cert-file ./cert.pfx \
--cert-password "CERT_PASSWORD"

Alternatively, use cert-manager with Let's Encrypt for automated certificate management.

Install

helm install beacon ./deploy/helm/watchlight-beacon \
-n watchlight \
-f ./deploy/helm/watchlight-beacon/values-azure.yaml

To use Azure Database for PostgreSQL instead of the built-in chart:

helm install beacon ./deploy/helm/watchlight-beacon \
-n watchlight \
-f ./deploy/helm/watchlight-beacon/values-azure.yaml \
--set postgresql.enabled=false \
--set global.externalDatabase.url="postgres://beacon:PASSWORD@beacon-db.postgres.database.azure.com:5432/beacon?sslmode=require"

Validation

Check pod status

kubectl get pods -n watchlight

All pods should reach Running status within a few minutes.

Verify the ingress

kubectl get ingress -n watchlight

The ADDRESS column should show the Application Gateway's public IP.

Health checks

# Registry API
curl -s https://registry.example.com/api/v1/health | jq .

# Registry frontend
curl -s -o /dev/null -w "%{http_code}" https://registry.example.com/

Smoke test

# List registered agents
curl -s https://registry.example.com/api/v1/agents | jq .

# Check wl-discover logs
kubectl logs -n watchlight -l app.kubernetes.io/name=wl-discover --tail=20

Production Hardening

High availability

The Azure values file enables HPA and PodDisruptionBudgets:

  • wl-registry: 2-10 replicas, minimum 1 available during disruptions
  • wl-registry-frontend: 2 replicas

AKS distributes pods across availability zones when using zone-redundant node pools:

az aks nodepool update \
--resource-group watchlight-beacon-rg \
--cluster-name watchlight-beacon \
--name nodepool1 \
--zones 1 2 3

Monitoring

Enable Azure Monitor for containers:

az aks enable-addons \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--addons monitoring \
--workspace-resource-id /subscriptions/SUB_ID/resourceGroups/RG/providers/Microsoft.OperationalInsights/workspaces/WORKSPACE

For Prometheus-based monitoring, enable the Azure Monitor managed service for Prometheus:

az aks update \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--enable-azure-monitor-metrics

Beacon services expose /metrics endpoints. The Helm chart includes ServiceMonitor resources that the managed Prometheus collector scrapes automatically.

Backup

  • Azure Database for PostgreSQL: Automated backups are enabled by default with 7-day retention. Geo-redundant backup is available for disaster recovery.
  • Configuration: Store your values file in version control.

Scaling considerations

ComponentScaling strategy
wl-registryHPA on CPU (included in values).
wl-registry-frontendHPA or fixed 2+ replicas.
wl-discoverDaemonSet -- scales automatically with cluster size.
PostgreSQL (Flexible Server)Vertical scaling via SKU change. Read replicas for read-heavy workloads.

Network security

  • Use Azure CNI for pod-level network policies.
  • Azure Database for PostgreSQL Flexible Server supports VNet integration -- the database is not exposed to the public internet.
  • Apply Kubernetes NetworkPolicy resources to restrict pod-to-pod traffic.
  • Consider using a private AKS cluster with an internal load balancer if Beacon should not be exposed publicly.

Managed identity best practices

AKS managed identity provides keyless authentication to Azure services. Avoid storing Azure credentials as Kubernetes secrets when possible:

# Assign the managed identity access to Key Vault
IDENTITY_ID=$(az aks show \
--resource-group watchlight-beacon-rg \
--name watchlight-beacon \
--query 'identityProfile.kubeletidentity.objectId' -o tsv)

az keyvault set-policy \
--name beacon-vault \
--object-id "$IDENTITY_ID" \
--secret-permissions get list