Deploy on Azure AKS
This guide is for the IT lead deploying Sema4.ai self-hosted edition into your Azure AKS environment. It assumes you're comfortable operating AKS — it doesn't cover general Kubernetes administration.
The application is distributed as a Helm chart installed into an existing AKS cluster. A single cluster can run multiple installations, but each must be in its own dedicated namespace.
For a single-VM install with no Kubernetes cluster to manage, see Azure VM instead. Customers with stricter governance or compliance requirements can work with Sema4.ai to design a tailored architecture. A reference Terraform module for Azure is available on request.
Provisioning the infrastructure in the bill of materials moves at the speed of your procurement, network, IAM, and security teams — anywhere from 2 days to 2 weeks. The Sema4.ai install itself is under 90 minutes, and a POC can run the same day.
Part 1 — Pre-deployment bill of materials
Hand this to procurement and your cloud/security teams on Day 0.
Decide these carefully — they're painful to retrofit:
- Hostname — TLS, OIDC redirect URIs, and ingress all derive from it; changing it later means re-issuing certs and reconfiguring your IdP.
- Region — moving regions later means a rebuild.
Components
| Category | Component | Spec / SKU | Notes |
|---|---|---|---|
| Compute | AKS cluster + dedicated namespace | A node pool with e.g. Standard_D4s_v6 (4 vCPU, 16 GiB) as the minimum node size. The cluster must have the OIDC issuer and Workload Identity enabled | Hosts the application compute. One application instance per namespace |
| Network | Cluster ingress | An ingress setup that routes traffic to the Sema4.ai application from end users and API clients | Yours to provide and operate. The application serves plain HTTP on port 8001 with a /health/live probe; terminate TLS in your ingress. The application is typically configured with service type ClusterIP or LoadBalancer |
| Network | DNS record | Hostname for the workspace, e.g. sema4-agents.<customer>.com → the ingress endpoint | |
| Data | PostgreSQL | Azure DB for PostgreSQL Flexible Server, PG 17+. Low-load: B2s (2 vCPU, 4 GB), 100 GB. Production: DC2ads-v6 (2 vCPU, 8 GB), 100 GB | Primary data storage for the application. Reachable from the cluster; public network access disabled. Allow-list the uuid-ossp extension via the azure.extensions server parameter (plpgsql, also required, is built in). The application enables the extensions itself, so its database user must be able to run CREATE EXTENSION |
| Data | Blob Storage | Azure Storage Account, Standard, ZRS, one container for the deployment. A configurable key prefix lets multiple deployments share one container | Stores files and data frames. Restrict network access to the cluster's network or a private endpoint |
| Data | Key Vault + RSA KEK | Azure Key Vault (Standard), same region as the cluster, with an RSA key (≥2048-bit) with wrapKey and unwrapKey operations | Envelope encryption of secrets at rest. You provide the versioned key identifier (https://<vault>.vault.azure.net/keys/<name>/<version>) in your values file |
| Identity | OIDC IdP app | App registration in Entra ID / Okta / Auth0 with redirect URI https://<hostname>/oidc/login/callback, logout URI https://<hostname>/oidc/logout/callback, scopes openid profile email, group claims if access-restricted | Discovery URL, Client ID, and Client Secret needed at install. See Identity providers (OIDC) |
| Identity | Managed identity → service account | A user-assigned managed identity with a federated identity credential binding it to the application's Kubernetes service account (Workload Identity (opens in a new tab)) | Roles: Get / WrapKey / UnwrapKey on the Key Vault KEK + Storage Blob Data Contributor on the storage account |
| Access | Administrative Azure & AKS access | Suitable Azure and cluster permissions for the deploying administrator, plus kubectl and helm on their workstation | Just-in-time access acceptable |
| Egress | Outbound HTTPS | Unrestricted egress recommended. Needed to reach the Sema4.ai services (image + chart pull, licensing, updates) plus your LLMs and MCP servers | See the network endpoints for the Sema4.ai hosts, and Add networking rules |
Ingress is your responsibility. The application serves plain HTTP on
port 8001 with a /health/live health probe; you expose it with your own
ingress controller or load balancer, terminate TLS there, and decide whether
it is internet-facing or internal. The values template below ships a generic
ingress example — adapt the class, annotations, and service type to your
environment. If you use the AKS application routing add-on (managed
NGINX), the template includes a commented-out starting point for it,
including the TLS certificate sync from Key Vault.
Part 2 — Deployment steps
Step 1: Pick the hostname (foundational)
Decide the hostname (e.g. finance-agents.company.com) on a domain you control — whether it resolves publicly or only internally is your choice. TLS, the OIDC redirect URI, and the ingress configuration all derive from it. You'll point DNS at your ingress endpoint later (Step 7).
Step 2: Register the OIDC application
Register an OIDC application in your identity provider and capture the Discovery URL, Client ID, and Client Secret for your values file. Use:
- Redirect URI:
https://<hostname>/oidc/login/callback - Logout URI:
https://<hostname>/oidc/logout/callback - Scopes:
openid,profile,email - Authorization code flow with PKCE where supported; restrict to the allowed group(s) if your IdP supports it.
Follow the guide for your provider: Microsoft Entra ID · Auth0 · Okta.
Step 3: Provision Azure infrastructure
Either apply the reference Terraform (available from Sema4.ai on request), or provision yourself via Bicep, ARM, or the portal using the bill of materials as the spec. The end state must include:
- An AKS cluster with the OIDC issuer and Workload Identity enabled, an ingress controller, and
kubectlaccess configured to that cluster (your AKS admin provides the kubeconfig context — you'll need it for the Helm install). Capture the cluster's OIDC issuer URL (az aks show --query oidcIssuerProfile.issuerUrl). - PostgreSQL Flexible Server 17+ with the
uuid-osspandplpgsqlextensions available (the application must be able to enable them), reachable from the cluster; capture host, port, and admin credentials. - A storage account with one blob container for the deployment (note any key prefix).
- A Key Vault with an RSA KEK (≥2048-bit,
wrapKey/unwrapKey); capture the versioned key identifier (https://<vault>.vault.azure.net/keys/<name>/<version>). - A user-assigned managed identity with Get / WrapKey / UnwrapKey on the KEK and Storage Blob Data Contributor on the storage account, plus a federated identity credential with the cluster's OIDC issuer URL and subject
system:serviceaccount:<your-namespace>:<service-account-name>. The service account name must match the one in your values file (Step 5) — the chart creates the service account at install. Capture the identity's client ID.
Step 4: Create the application database
The application needs a dedicated database on your PostgreSQL server. Connect to the management database (postgres) with a SQL client and create one:
CREATE DATABASE <database-name>;Capture the database name and the admin username and password — you'll enter them in your values file.
The application enables the uuid-ossp and plpgsql extensions in this database itself on first start, so the user you provide must be able to run CREATE EXTENSION (an admin user is). On Flexible Server, uuid-ossp must also be allow-listed via the azure.extensions server parameter (per the bill of materials).
Step 5: Prepare your my-values.yaml
Create the values file that configures your deployment before you start the install. Start from this template and replace every REPLACE_ME with your values (the external URL drives the OAuth callback, so it must match the hostname you registered with your IdP; the service account name and namespace must match the federated identity credential). Keep this file — you reuse it for upgrades.
my-values-azure-aks.example.yaml# Helm values for the Sema4.ai Deployment on Azure AKS
#
# Only chart-default overrides and the name-derived/shared-infra fields are
# listed below. The image (registry/repository/tag) comes from the chart — tag
# is supplied via --set on helm install. The Replicated SDK injects the proxy
# pull secret from its license, so no imagePullSecrets entry is needed.
# The chart creates the service account. Its name and namespace must match the
# federated identity credential on the user-assigned managed identity, and the
# annotation points at that identity's client ID.
serviceAccount:
create: true
name: REPLACE_ME
annotations:
azure.workload.identity/client-id: "REPLACE_ME"
# Opts the pods into Azure Workload Identity so the application can reach Blob
# Storage and Key Vault with the federated managed identity.
podLabels:
azure.workload.identity/use: "true"
# Ingress is YOUR responsibility: the application serves plain HTTP on port
# 8001 with a /health/live health probe — expose it with your ingress
# controller or load balancer, terminate TLS there, and decide whether it is
# internet-facing or internal. Below is a generic example for an ingress
# controller routing to a ClusterIP service (the chart default is NodePort);
# adapt className, annotations, and the service type to your environment.
service:
type: ClusterIP
ingress:
enabled: true
className: REPLACE_ME
annotations: {}
hosts:
- host: "REPLACE_ME"
paths:
- path: /
pathType: Prefix
port: http
tls: []
# Starting point for the AKS application routing add-on (managed NGINX) —
# replace the generic className/annotations/tls above with these. The
# tls-cert-keyvault-uri annotation syncs the TLS certificate from Key Vault;
# it requires the vault to be attached to the add-on
# (az aks approuting update --attach-kv). The add-on's default NGINX is
# public — for an internal (private) deployment, create an internal
# controller via its NginxIngressController resource and use that class.
#
# className: webapprouting.kubernetes.azure.com
# annotations:
# kubernetes.azure.com/tls-cert-keyvault-uri: "https://<vault>.vault.azure.net/certificates/<name>"
# tls:
# - hosts:
# - "<hostname>"
# # The add-on syncs the Key Vault certificate into this secret, named
# # keyvault-<ingress-name>; with the release named 'spar' this is:
# secretName: keyvault-spar
config:
infrastructurePlatform: "azure"
azure:
storageAccountName: "REPLACE_ME"
storageContainerName: "REPLACE_ME"
blobKeyPrefix: "REPLACE_ME"
# Versioned Key Vault key identifier of the RSA KEK, in the form
# https://<vault>.vault.azure.net/keys/<name>/<version>
keyVaultKeyUrl: "REPLACE_ME"
postgres:
host: "REPLACE_ME"
port: "5432"
user: "REPLACE_ME"
password: "REPLACE_ME"
database: "REPLACE_ME"
# Public base URL (drives OAuth callback + MCP public-API base URLs).
externalUrl: "REPLACE_ME"
# authMode defaults to 'oidc' in the chart.
workroom:
# Register redirect URI <externalUrl>/oidc/login/callback with your IdP.
oidcClientId: "REPLACE_ME"
oidcClientSecret: "REPLACE_ME"
oidcServer: "REPLACE_ME"
# Installs the Sema4.ai MCP Gallery container
mcpGallery:
enabled: trueStep 6: Install the application with Helm
Before you start, make sure your Azure CLI session and kubectl context point
at the target AKS cluster — e.g. authenticate (az login) and run
az aks get-credentials --resource-group <rg> --name <cluster>. Otherwise the
install fails with a cluster-reachability error.
Get the install details from the Sema4.ai Enterprise portal (opens in a new tab). You'll receive an email invitation — activate your account, then sign in. Your Team is your organization; if the same email is used for several self-hosted deployments, switch between them with the Team dropdown.
Go to Install and choose Helm. In step 1:
- Instance Name — a label for the deployment in the portal tooling.
- Kubernetes Distribution — choose Azure AKS.
- Cluster Network Availability and Registry Access — choose the options that match your local setup (whether outbound requests are allowed or go through an HTTPS proxy, and whether your workstation can reach the cluster as well as the registry).
Then click Continue.
The Instance Name is only a label in the portal tooling — it is not the deployment's hostname or subdomain. The hostname is the one you chose in Step 1.
In step 2, the portal walks you through the install:
-
Select a version.
-
Export credentials and log in with the commands shown:
export AUTH_TOKEN=<token from the portal> helm registry login registry.sema4.ai --username <your-email> --password $AUTH_TOKEN -
Skip "Create values override file" — you already prepared
my-values.yamlin Step 5. -
Skip "Install preflight plugin" — it isn't needed for this install.
-
Install the chart. Take the
helm installcommand from the portal, point--valuesat your file, and add your namespace:helm install spar oci://registry.sema4.ai/sema4ai/prod-selfhosted/spar \ --version <version> \ --values my-values.yaml \ --namespace <your-namespace>
The command you copy from the portal omits the namespace — append
--namespace <your-namespace> yourself.
Step 7: Point DNS at your ingress
Point your hostname at whatever endpoint exposes the application — this depends on your ingress controller (the application routing add-on's public IP, an Application Gateway, an existing gateway, etc.), so the exact target and record type are yours to determine. Create the DNS record in your DNS provider (for example, Azure DNS) resolving the hostname to that endpoint. Sign-in won't complete until the hostname resolves and TLS is serving.
Step 8: Validate
- Browse to
https://<hostname>— login should redirect to your IdP. - Sign in with a permitted user; you should land in the Sema4.ai workspace.
- Run a smoke-test agent to confirm the data plane (Postgres, Blob).
Keep your my-values.yaml — you reuse it for upgrades. See
Update the Sema4.ai application.
Next steps
With the application running, continue to First-time setup to connect LLMs, set up MCP OAuth, and configure the rest of the workspace.