Skip to main content

Deploying on Azure

Tinkr uses Managed Identity — no client secrets needed in production.


Required RBAC roles

Assign at the subscription or resource group scope:

RolePurpose
Monitoring ReaderRead Azure Monitor metrics
Log Analytics ReaderRun KQL queries against Log Analytics
PRINCIPAL_ID=$(az identity show \
--name tinker-identity \
--resource-group my-rg \
--query principalId -o tsv)

az role assignment create \
--assignee $PRINCIPAL_ID \
--role "Monitoring Reader" \
--scope /subscriptions/SUBSCRIPTION_ID

az role assignment create \
--assignee $PRINCIPAL_ID \
--role "Log Analytics Reader" \
--scope /subscriptions/SUBSCRIPTION_ID

# Create managed identity
az identity create --name tinker-identity --resource-group my-rg

IDENTITY_ID=$(az identity show --name tinker-identity --resource-group my-rg --query id -o tsv)
CLIENT_ID=$(az identity show --name tinker-identity --resource-group my-rg --query clientId -o tsv)

# Store secrets in Key Vault
az keyvault secret set --vault-name my-vault --name anthropic-api-key --value "sk-ant-..."
az keyvault secret set --vault-name my-vault --name tinker-api-keys \
--value '[{"hash":"<sha256>","subject":"alice","roles":["oncall"]}]'

# Deploy
az containerapp create \
--name tinker \
--resource-group my-rg \
--environment my-env \
--image <your-acr>.azurecr.io/tinker:latest \
--user-assigned $IDENTITY_ID \
--target-port 8000 \
--ingress external \
--env-vars \
TINKR_BACKEND=azure \
AZURE_LOG_ANALYTICS_WORKSPACE_ID=<workspace-id> \
AZURE_SUBSCRIPTION_ID=<subscription-id> \
AZURE_RESOURCE_GROUP=my-rg \
AZURE_CLIENT_ID=$CLIENT_ID \
--secrets \
anthropic-api-key=keyvaultref:<vault-uri>/secrets/anthropic-api-key,identityref:$IDENTITY_ID \
tinker-api-keys=keyvaultref:<vault-uri>/secrets/tinker-api-keys,identityref:$IDENTITY_ID

AKS

k8s/tinker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tinker
spec:
replicas: 1
selector:
matchLabels:
app: tinker
template:
metadata:
labels:
app: tinker
azure.workload.identity/use: "true"
spec:
serviceAccountName: tinker-sa
containers:
- name: tinker
image: <your-acr>.azurecr.io/tinker:latest
ports:
- containerPort: 8000
env:
- name: TINKR_BACKEND
value: azure
- name: AZURE_LOG_ANALYTICS_WORKSPACE_ID
value: "<workspace-id>"
- name: AZURE_SUBSCRIPTION_ID
value: "<subscription-id>"
- name: AZURE_RESOURCE_GROUP
value: "my-rg"
envFrom:
- secretRef:
name: tinker-secrets

Required environment variables

VariableDescription
AZURE_LOG_ANALYTICS_WORKSPACE_IDLog Analytics workspace ID
AZURE_SUBSCRIPTION_IDAzure subscription ID
AZURE_RESOURCE_GROUPResource group containing monitored resources
AZURE_CLIENT_IDClient ID of Managed Identity (for pod identity / Container Apps)

For local development with az login, DefaultAzureCredential picks up your CLI credentials automatically — no environment variables needed.


Profile configuration

~/.tinkr/config.toml
[profiles.azure-prod]
backend = "azure"
workspace_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
resource_group = "prod-rg"