Skip to content

Deploying on Azure

This page describes the end-to-end deployment process for a customer-owned Azure tenant. It lists exactly what the customer must do, what Sight Machine will do, and in what order.


Term Definition
Subscription One dedicated Azure subscription per customer, scoped entirely to that customer
Cluster One AKS (Kubernetes) cluster per subscription (or per region); named smai-<customer>-<purpose>-<region>
Environment One per physical facility — a Kubernetes namespace with its own database, message stream, and application instance
UAMI User-assigned managed identity — the keyless credential the Sight Machine deploy pipeline uses to act in your Azure tenant
Keycloak The in-cluster identity broker. Your corporate IdP federates to Keycloak; the application trusts Keycloak. You register one app in your IdP per cluster (see Phase 1.5)
Application hostname Where a facility’s app is reached: <facility>.<customer>.sightmachine.ai
Issuer hostname Where Keycloak/sign-in lives for the cluster: auth.<customer>.sightmachine.ai

All items the customer must complete before or during deployment. Sight Machine will walk through each at the appropriate phase.

Action required Example / Options Customer Entered Values For Deployment
Provision a dedicated Azure subscription EA enrollment or pay-as-you-go
Provide Subscription ID to Sight Machine xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Verify and request vCPU quota in target region Standard Dadsv7: 64 vCPU · Standard Eadsv6: 24 vCPU (production profile — see § 1.2)
Confirm target Azure region eastus2, westus2, westus3, southcentralus, mexicocentral, westeurope, northeurope
Bring LLM provider(s) and obtain API key(s) All via the Bifrost gateway — one or more providers (Anthropic, Azure OpenAI, Foundry, OpenAI, …), shared or per-provider keys
Register one OAuth/OIDC app per cluster in your corporate IdP Entra ID, Google Workspace, Okta, or any OIDC provider
Add the Keycloak broker redirect URI to that IdP app https://auth.<customer>.sightmachine.ai/realms/<customer>/broker/customer-<idp>/endpoint
Provide IdP app details to Sight Machine Client ID · Client secret · Issuer URL (Okta/OIDC) · Allowed group IDs or email domain
Apply Sight Machine bootstrap Terraform file tofu apply of customer-bootstrap.tf
Provide three Terraform outputs to Sight Machine client_id, tenant_id, subscription_id
Apply platform admin role definition tofu apply of smai-platform-role.tf
Configure ClickHouse backup storage target Azure Files or Blob CSI-backed PVC

Note on credentials: you do not seed per-facility OAuth client secrets. The per-environment Keycloak client credentials are generated automatically by Sight Machine’s tooling. Your only auth input is the single corporate IdP app per cluster above.


Create a dedicated Azure subscription for the Sight Machine deployment. This subscription must be:

  • In Active billing state
  • Owned by or reachable from your Azure enrollment or pay-as-you-go account
  • Separate from subscriptions used for other workloads

Provide Sight Machine with the Subscription ID at engagement kickoff.

The AKS cluster requires available vCPU quota in your chosen Azure region. Check and request increases before deployment begins — Microsoft quota increases can take 1–5 business days.

A production cluster uses Sight Machine’s standard production node-pool profile: the general-purpose Dadsv7 family for the system, workload, and jobs pools, and the memory-optimized Eadsv6 family for ClickHouse (analytics is memory-bound, so it gets more RAM per core). Request quota in your target region for these two families:

VM Family Min. vCPU quota Pools it covers
Standard Dadsv7 64 System (D4ads_v7) + Workload (D4ads_v7, 2–20 nodes) + Jobs (D8ads_v7, 0–20, scales to zero)
Standard Eadsv6 (memory-optimized) 24 ClickHouse (E8ads_v6, 8 vCPU / 64 GiB, 1–3 nodes)

These figures are a conservative starting point for the standard profile. Sight Machine right-sizes ClickHouse memory and the jobs node size against your representative data volume; if a sizing review raises a pool, we’ll confirm the revised quota with you before deployment. A small POC may run on a smaller, single-family footprint — Sight Machine confirms the exact profile at kickoff.

Terminal window
# Check current quota for a VM family in your target region
az vm list-usage --location <region> --output table | grep -i "standard D"

If any family is below the required amount, open a quota increase request in the Azure portal before the deployment date. This is just quota — Sight Machine builds its clusters to scale, so initial machine counts are much lower than the quota ceiling.

Choose an Azure region. Sight Machine will verify that AKS, PostgreSQL Flexible Server, and Event Hubs Standard are all available there.

Commonly supported regions: eastus2, westus2, westus3, southcentralus, mexicocentral, westeurope, northeurope.

1.4 Base domain and hostnames (no action required)

Section titled “1.4 Base domain and hostnames (no action required)”

Each cluster gets hostnames under Sight Machine’s managed sightmachine.ai domain. Sight Machine creates and manages all DNS — no DNS action is required from you. For reference, a cluster exposes:

  • Application hostname per facility — <facility>.<customer>.sightmachine.ai (e.g. chicago.acme.sightmachine.ai)
  • Issuer hostname for the cluster — auth.<customer>.sightmachine.ai (this is the Keycloak sign-in host your IdP federates to; you will reference it in Phase 1.5)

1.5 Authentication: register one IdP app per cluster

Section titled “1.5 Authentication: register one IdP app per cluster”

Sign-in is brokered through an in-cluster Keycloak identity provider. Your corporate IdP federates to Keycloak — you register one OAuth/OIDC application per cluster (not per facility). Sight Machine wires Keycloak to that app and generates all per-facility client credentials internally.

Step 1 — Register an app in your IdP (Entra ID, Google, Okta, or any OIDC provider).

Step 2 — Add the Keycloak broker redirect URI to that app. This is the one URL Sight Machine cannot add on your behalf (it lives in your IdP):

https://auth.<customer>.sightmachine.ai/realms/<customer>/broker/customer-<idp>/endpoint

where <idp> is azure-ad, google, okta, or oidc. Sight Machine confirms the exact <customer> realm slug and <idp> alias with you at kickoff.

Step 3 — Provide these to Sight Machine over the secure channel (Phase 4):

Item Notes
Client ID From your IdP app
Client secret The secret value (not the secret ID)
Issuer URL Required for Okta / generic OIDC (e.g. https://<customer>.okta.com/oauth2/default); Entra/Google are derived automatically
Allowed access Group object ID(s) or an email domain (e.g. @customer.com) — controls who may sign in

Per-IdP specifics (Entra app-registration, Google OAuth client, Okta app integration) are walked through with you at kickoff.

All LLM calls route through an in-cluster Bifrost gateway — the agent never holds a model key directly. You can bring one or more providers, and you are not limited to a single model.

  • One or more providers. Configure any supported backend(s) — Anthropic, Azure OpenAI, Azure-hosted Anthropic on Foundry, OpenAI, Mistral, etc. — each serving one or more models. Sight Machine wires the provider catalog from what you give us.
  • Keys: shared or per-provider. A single shared provider key is the simplest case. To bring multiple providers on different accounts, each provider can carry its own API key (provider A on key X, provider B on key Y).
  • Runtime switching. An administrator picks the active provider/model from the configured catalog inside the application — no redeploy.

What you provide: an API key for each provider you want enabled (plus the resource endpoint for any Azure-hosted provider). Sight Machine confirms the catalog (provider names + model lists) and the exact Key Vault secret name for each key with you. These are seeded in Phase 4.

Do not send credentials over email — Sight Machine provides a secure channel at the appropriate step.


This is the only infrastructure step the customer must perform before Sight Machine can deploy. It creates a keyless identity that Sight Machine’s pipeline will use to provision resources in your subscription.

Sight Machine’s deploy pipeline authenticates to your Azure tenant using OIDC federated credentials — no passwords or long-lived secrets are ever shared. You create a user-assigned managed identity (UAMI) in your own subscription, federate it to Sight Machine’s GitHub deploy pipeline, and grant it scoped permissions. You retain full control and can revoke access unilaterally at any time.

2.1 Sight Machine emits the bootstrap artifact

Section titled “2.1 Sight Machine emits the bootstrap artifact”

Sight Machine runs the following command and delivers a single Terraform/OpenTofu file (customer-bootstrap.tf) to your team:

Terminal window
# Run by Sight Machine — you receive the output file
smai customer bootstrap \
--subscription <your-sub-id> \
--resource-group rg-smai-<customer>-<purpose> \
--location <region> \
--github-environment deploy-<customer>-<purpose> \
--out customer-bootstrap.tf

The generated file creates only the following resources — nothing else:

Resource Name Purpose
Resource group rg-smai-<customer>-<purpose> Container for all deployment resources
User-assigned managed identity (UAMI) id-smai-deploy-<customer>-<purpose>-<region> The deploy identity Sight Machine’s pipeline assumes
Federated credential (on the UAMI) Binds the UAMI to Sight Machine’s GitHub deploy pipeline via OIDC. No secret is created — trust is based on a signed GitHub token only
Role assignment Contributor + Role Based Access Control Administrator on the resource group Allows the UAMI to create and manage resources, and to make role assignments for managed identities it subsequently creates (e.g. the Key Vault reader identity)

This file contains no secrets. It is identity-only and can be reviewed by your security team before being applied.

Heads-up for ABAC-restricted tenants: granting Role Based Access Control Administrator is a role-assignment write. If your tenant restricts those via Azure ABAC conditions (e.g. a conditioned-Owner policy), the grant may need to be applied by an unconditioned administrator or via a PIM-elevated session. Flag this to whoever applies the file so it doesn’t fail at apply time.

2.2 Provide three outputs to Sight Machine

Section titled “2.2 Provide three outputs to Sight Machine”

After tofu apply completes, three values are emitted as outputs. Share these with Sight Machine through a secure channel:

Terminal window
tofu output client_id # The UAMI's client (application) ID
tofu output tenant_id # Your Azure AD tenant ID
tofu output subscription_id # Your Azure subscription ID

These are public identifiers — not secrets. Sight Machine uses them to configure the deploy pipeline so it assumes your UAMI via OIDC when provisioning your cluster.


Phase 3 — Sight Machine provisions the cluster

Section titled “Phase 3 — Sight Machine provisions the cluster”

With the three output values from Phase 2, Sight Machine triggers the deployment pipeline. No further customer action is required during this phase.

Sight Machine provisions all Azure infrastructure and installs the platform, running entirely as your UAMI inside your subscription:

Azure resources provisioned:

Resource Name pattern Notes
AKS Kubernetes cluster smai-<customer>-<purpose>-<region> Multi-pool: system, workload, clickhouse, jobs
Virtual network + subnets vnet-smai-<customer>-<purpose>-<region> Subnets for AKS, PostgreSQL, Event Hubs
PostgreSQL Flexible Server pg-<customer>-<purpose>-<region> Private, VNet-integrated; one logical database per environment
Event Hubs namespace ehns-<customer>-<purpose>-<region> Kafka-compatible; one topic per environment
Azure Key Vault kv-<customer>-<purpose>-<region> RBAC-enabled; all platform secrets stored here
Managed identity (ESO reader) id-smai-eso-kv-reader-<suffix> Keyless, federated; used by in-cluster secrets sync
Terraform state storage sttf<customer><purposeshort> Auto-provisioned; billed to your subscription
Private DNS zone <cluster>.postgres.database.azure.com Private PostgreSQL access from AKS
Container registry (cross-tenant only) Auto-provisioned in your sub Only required when your Entra tenant is separate from Sight Machine’s. Platform images are mirrored here from SM’s registry

In-cluster platform add-ons installed:

Add-on Purpose
Envoy Gateway Ingress and TLS termination for all environments
cert-manager + Let’s Encrypt Automatic TLS certificate provisioning
External Secrets Operator Syncs Key Vault secrets into Kubernetes
external-dns Creates the public DNS records for each hostname automatically (in Sight Machine’s DNS)
ClickHouse Operator + ClickHouse instance Time-series analytics database
KEDA Event-driven autoscaling for the jobs pool (scales long-job workers, including scale-to-zero)
Keycloak In-cluster identity broker for application authentication

Per-environment resources provisioned (one set per facility):

  • PostgreSQL logical database
  • Event Hubs topic
  • ClickHouse database
  • Key Vault secrets scoped to the environment

Phase 4 — Credentials seeding (post-deployment)

Section titled “Phase 4 — Credentials seeding (post-deployment)”

The cluster Key Vault is pre-seeded with a placeholder LLM key during provisioning, so the deployment completes without your real key — the platform comes up fully healthy and only LLM-backed features wait on the real key. Supplying it is a post-deployment step: you (or Sight Machine, from values you provide over the secure channel) overwrite the placeholder in the Key Vault. There is no race to seed before deploy, and pods do not error while the placeholder is in place.

For customer-owned tenants, Sight Machine never holds these credentials long-term. The customer (or Sight Machine, working from values you provide over the secure channel) overwrites the placeholder in the Key Vault using either the smai CLI or the Azure portal.

Via CLI (use --stdin so the value never lands in shell history):

Terminal window
# LLM provider key(s) — all LLM access is via the Bifrost gateway.
# Single / shared key:
smai secrets set <cluster-name> bifrost-llm-api-key --stdin
# Multiple providers on separate accounts — one secret per provider
# (Sight Machine gives you the exact name for each):
smai secrets set <cluster-name> <provider-key-secret> --stdin

Via Azure portal: Navigate to the Key Vault (kv-<customer>-<purpose>-<region>) → Secrets → Generate/Import. Use the secret name(s) below exactly.

Secret name Value When
bifrost-llm-api-key The provider API key the Bifrost gateway uses (shared / single-provider case) Default
(one secret per provider) A separate API key per provider when bringing multiple LLMs on different accounts Multi-provider — Sight Machine gives you the exact secret name per provider

All LLM access is via Bifrost. There are no separate anthropic-api-key / azure-ai-resource / custom-ai-resource secrets to seed on a standard deployment — the agent reaches every model through the gateway, which holds the provider key(s).

You do NOT seed OAuth secrets here. The corporate-IdP credentials you provided in Phase 1.5 are configured once per cluster into Keycloak’s IdP broker by Sight Machine. The per-facility Keycloak client credentials (<env-id>-oauth-client-*) are generated automatically by smai on deploy — there is nothing for you to seed per environment.

Timing — seed at the end, not before. The deployment completes without your real key: provisioning seeds a placeholder so the platform boots healthy. The Bifrost gateway starts and fails LLM calls closed until a real key is present — it does not crash, and no pod stays in a startup-error state. Overwrite the placeholder with your real key any time after the cluster is up; the gateway picks it up automatically (a brief restart). Until then, only LLM-backed features are unavailable — the rest of the platform is fully operational.

SM-hosted clusters: Sight Machine manages this step.


These steps run after the application is deployed. Sight Machine will notify you when they are ready.

Sight Machine manages all DNS under sightmachine.ai and creates the records automatically as each environment deploys — no DNS action is required from you. Two records are created per cluster:

<facility>.<customer>.sightmachine.ai → <load-balancer-IP> (application)
auth.<customer>.sightmachine.ai → <load-balancer-IP> (Keycloak / sign-in)

Example: chicago.acme.sightmachine.ai and auth.acme.sightmachine.ai.

TLS certificate issuance via Let’s Encrypt begins automatically once each record resolves (typically within ~1 minute). No certificate management is required on your side.

Two redirect URIs are involved, and they’re handled differently:

  • Keycloak → application (https://<facility>.<customer>.sightmachine.ai/oauth2/callback): registered automatically by smai env deploy on the internal Keycloak client. No action required from you.
  • Your IdP → Keycloak (the broker redirect URI): this is the one you registered in your IdP app in Phase 1.5. If sign-in fails with a redirect-mismatch error, confirm that URI is present in your IdP app exactly as specified.

Sight Machine runs smoke tests confirming:

  • DNS records resolve and TLS certificates are issued and valid
  • The OAuth login flow (your IdP → Keycloak → application) completes successfully
  • Application APIs respond
  • Data ingestion path is reachable

Phase 6 — Required operational gates (customer-owned tenants only)

Section titled “Phase 6 — Required operational gates (customer-owned tenants only)”

For customer-owned tenants, the following are hard requirements before Sight Machine hands over the environment. They are not optional.

Sight Machine provisions the backup tooling. You must provide a durable storage destination in your subscription.

PostgreSQL is backed up automatically with a minimum 7-day point-in-time restore window. You may raise the retention period (up to 35 days) or enable geo-redundant backup by updating your cluster configuration.

ClickHouse requires a customer-owned durable storage claim. Before environment handover, configure the following in your cluster’s platform settings:

backup:
snapshot:
enabled: true
schedule: "0 4 * * *" # adjust to match your RPO requirement
includeData: true
target:
existingClaim: "<your-backup-pvc>" # PVC backed by Azure Files or Blob CSI in your subscription

Sight Machine staff require named identities in your subscription for ongoing platform administration. Apply the smai-platform-admin role definition in your subscription before access is created for the Sight Machine users.

Assign each Sight Machine staff member on the list Sight Machine provides to the cluster resource group with the smai-platform-admin role. The list gives each person’s name, email, role, country, and whether they need Privileged Identity Management (PIM) elevation.

To get the list, or with any question about this access, email support@sightmachine.com.

Users marked PIM: Yes require time-limited elevation to Contributor for specific operations such as upgrades and incident remediation. Enable Privileged Identity Management for those users in your Azure subscription — they activate the role on-demand for the duration of a task and deactivate it immediately after. Not all Sight Machine staff require PIM access.

smai-platform-admin custom role — permission set

Section titled “smai-platform-admin custom role — permission set”

Sight Machine will provide this role definition as a Terraform file. The permissions below are what it grants — share with your security team for review before applying.

Scope: Apply at the subscription level when possible (/subscriptions/<subscription-id>). This covers all current and future clusters in the subscription without requiring re-application per cluster. If your policy requires resource-group-level grants, apply once per cluster resource group instead.

What this grants, in plain terms: read access to cluster/resource metadata and Event Hubs, the ability to pull a cluster-user kubeconfig and read/exec/delete pods for troubleshooting, and read access to Event Hub messages. It cannot create, modify, or delete the AKS cluster itself, and it cannot read or write Kubernetes Secrets. Note that listClusterUserCredential plus pods/exec together provide broad in-cluster operational access (the intent for an admin role) — your security team should review with that in mind.

{
"properties": {
"permissions": [
{
"actions": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/listClusterUserCredential/action",
"Microsoft.Resources/subscriptions/resourceGroups/read",
"Microsoft.Resources/subscriptions/read",
"Microsoft.Resources/subscriptions/locations/read",
"Microsoft.Resources/subscriptions/resources/read",
"Microsoft.EventHub/namespaces/read",
"Microsoft.EventHub/namespaces/eventhubs/read",
"Microsoft.EventHub/namespaces/eventhubs/consumergroups/read",
"Microsoft.Resources/resources/read",
"Microsoft.Resources/deployments/read"
],
"notActions": [
"Microsoft.ContainerService/managedClusters/delete",
"Microsoft.ContainerService/managedClusters/write"
],
"dataActions": [
"Microsoft.ContainerService/managedClusters/pods/read",
"Microsoft.ContainerService/managedClusters/pods/delete",
"Microsoft.ContainerService/managedClusters/pods/exec/action",
"Microsoft.ContainerService/managedClusters/services/read",
"Microsoft.ContainerService/managedClusters/namespaces/read",
"Microsoft.ContainerService/managedClusters/nodes/read",
"Microsoft.ContainerService/managedClusters/events/read",
"Microsoft.EventHub/namespaces/messages/receive/action"
],
"notDataActions": [
"Microsoft.ContainerService/managedClusters/secrets/read",
"Microsoft.ContainerService/managedClusters/secrets/write",
"Microsoft.ContainerService/managedClusters/configmaps/write"
]
}
]
}
}