Onboarding: Azure¶
This guide wires your Azure subscription into Argmin. It assumes one subscription and one customer-side workload identity (Kubernetes service account, GitHub Actions OIDC, or any OIDC issuer) that federates to the Argmin service principal.
Time required
~15 minutes, plus a single terraform apply.
What this grants Argmin¶
An Azure AD service principal authorized via Workload Identity Federation (preferred — no long-lived secrets) with three subscription-scoped read-only roles:
- Reader — visibility into all resources in the subscription (inventory).
- Cost Management Reader — actual billed amounts including EA/CSP discounts, via the Cost Management Query API.
- Monitoring Reader — Azure Monitor metrics + Log Analytics queries (Azure OpenAI / Cognitive Services usage attribution).
Optional (off by default; need additional resource IDs):
- APIM read — when AI inference flows through Azure API Management with the
llm-emit-token-metricpolicy. Scopes a Log Analytics workspace read. - Event Hubs read — when Azure OpenAI diagnostic logs land in an Event Hub.
The service principal has zero write access. The platform's
check_permissions.py enforces this; the role assignments are verifiable in
infra/azure/onboarding/main.tf.
No-WIF fallback
If you'd rather not use Workload Identity Federation, the module supports a
90-day client-secret fallback (use_federated_credential = false). The secret
is never exposed in Terraform outputs by default.
Step 1 — Get the values Argmin will provide¶
Email contact@argmin.co and ask for:
federated_credential_issuer— Argmin's OIDC issuer URL.federated_credential_subject— the subject claim Argmin signs into its federation token (typicallysystem:serviceaccount:argmin:argmin-processoror similar).
You will provide back to Argmin:
- The
client_idoutput (the service principal's application ID). - The
object_idoutput (the service principal's object ID — used for cross-tenant references if your tenant differs from Argmin's). - Your
subscription_id(for Argmin's audit trail).
Step 2 — Configure your terraform.tfvars¶
Create terraform.tfvars in infra/azure/onboarding/:
subscription_id = "00000000-0000-0000-0000-000000000000"
use_federated_credential = true
federated_credential_issuer = "https://<from Argmin>"
federated_credential_subject = "<from Argmin>"
# Optional surfaces (off by default). Ask Argmin which to enable based on where
# your Azure OpenAI inference actually runs.
enable_apim_access = false
enable_event_hub_access = false
A complete terraform.tfvars.example ships in the module directory.
Step 3 — Apply¶
cd infra/azure/onboarding
az login # or use a service-principal-authorized session
az account set --subscription <subscription_id>
terraform init
terraform plan # confirm the SP + role assignments
terraform apply
Outputs:
client_id,object_id— copy to your onboarding email.auth_method—workload_identity_federationorclient_secret.granted_roles— human-readable list of what was granted.
Step 4 — Verify¶
The verify script:
- Confirms the service principal exists.
- Lists role assignments at subscription scope and asserts each is one of Reader, Cost Management Reader, or Monitoring Reader.
- Attempts a write call and asserts it fails with
AuthorizationFailed. A success here is a security finding.
Step 5 — Hand the values to Argmin¶
Reply to your onboarding email with:
client_id: <terraform output>
object_id: <terraform output>
subscription_id: <your subscription>
tenant_id: <your AAD tenant id>
auth_method: workload_identity_federation
notes: <anything Argmin should know about your subscription layout>
Argmin responds within 1 business day confirming the federation handshake succeeded and ingestion has started.
Rotating credentials¶
- Workload Identity Federation — nothing to rotate; there are no long-lived secrets.
- Client-secret fallback — the secret has a 90-day TTL by design. Re-run
terraform applybefore expiry to generate a new one; Argmin will explain the encrypted hand-off.
Removing access¶
Deletes the application, the service principal, and all role assignments. Notify Argmin first so ingestion can pause cleanly.
Troubleshooting¶
| Symptom | Most likely cause |
|---|---|
| "AADSTS70021" / "no matching federated identity record" | federated_credential_subject mismatch — Argmin's signing subject doesn't match the module. |
| Cost Management returns empty | Cost Management uses tenant-scoped permissions for EA/CSP customers; ask Argmin whether your enrollment account ID must be added separately. |
| Azure OpenAI usage missing | Inference is going through APIM or an Event Hub; flip the matching enable_* flag and terraform apply. |
terraform apply fails on azuread_application |
The Terraform principal lacks Application.ReadWrite.OwnedBy. Run as a Global Administrator or have an admin grant it. |
Reference¶
- Module source:
infra/azure/onboarding/ - Verify script:
infra/azure/onboarding/scripts/verify.sh - Trust & security model
- Security policy: https://github.com/argmin-com/.github/blob/main/SECURITY.md