Skip to content

Manual Service Principal Setup - Azure CLI Commands

Quick reference for manually creating a service principal for Docker development.


Prerequisites

  • Azure CLI installed and logged in (az login)
  • Contributor + User Access Administrator role on subscription
  • Know your resource group and AI Services resource names

Step 1: Set Variables

# Your Azure resource names
RESOURCE_GROUP="ldfdev-rg"                    # Your resource group name
AI_RESOURCE_NAME="ldfdev-ai"                  # Your AI Services resource name
SP_NAME="loan-defenders-docker-dev"           # Service principal name

# Get subscription ID (automatic)
SUBSCRIPTION_ID=$(az account show --query id -o tsv)

Step 2: Verify Resources Exist

# Verify resource group
az group show --name "$RESOURCE_GROUP"

# Verify AI Services resource
az cognitiveservices account show \
  --name "$AI_RESOURCE_NAME" \
  --resource-group "$RESOURCE_GROUP"

Step 3: Create Service Principal with Role Assignment

# Create service principal with Cognitive Services OpenAI User role
# Scoped to specific AI Services resource only (least privilege)
az ad sp create-for-rbac \
  --name "$SP_NAME" \
  --role "Cognitive Services OpenAI User" \
  --scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$AI_RESOURCE_NAME" \
  --query "{appId: appId, password: password, tenant: tenant}" \
  -o json

Output will show:

{
  "appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

⚠️ IMPORTANT: Save these values immediately - the password cannot be retrieved later!


Step 4: Verify Role Assignment

# Get the client ID from previous step
CLIENT_ID="<appId from previous command>"

# Verify role assignment was created
az role assignment list \
  --assignee "$CLIENT_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$AI_RESOURCE_NAME" \
  --query "[].{Role:roleDefinitionName, Scope:scope}" \
  -o table

Expected output:

Role                              Scope
--------------------------------  ----------------------------------------------------------------
Cognitive Services OpenAI User    /subscriptions/.../accounts/ldfdev-ai


Step 5: Add to .env File

Add these credentials to your .env file in the repository root:

# ═══════════════════════════════════════════════════════════════════════════
# AZURE AUTHENTICATION - Service Principal for Docker
# ═══════════════════════════════════════════════════════════════════════════
AZURE_TENANT_ID=<tenant from step 3>
AZURE_CLIENT_ID=<appId from step 3>
AZURE_CLIENT_SECRET=<password from step 3>

Troubleshooting

Service Principal Already Exists

If you get "service principal already exists" error:

# Delete existing service principal
az ad sp delete --id $(az ad sp list --display-name "$SP_NAME" --query '[0].appId' -o tsv)

# Then re-run Step 3

Insufficient Permissions Error

You need one of these role combinations:

Option 1: Owner role

az role assignment create \
  --assignee "<your-user-email>" \
  --role "Owner" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

Option 2: Contributor + User Access Administrator

az role assignment create \
  --assignee "<your-user-email>" \
  --role "Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

az role assignment create \
  --assignee "<your-user-email>" \
  --role "User Access Administrator" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

Option 3: Application Administrator (Azure AD)

# Must be granted via Azure Portal:
# Azure AD → Roles and administrators → Application Administrator → Add assignment

Check Current Permissions

# Check your role assignments
az role assignment list \
  --assignee "$(az account show --query user.name -o tsv)" \
  --resource-group "$RESOURCE_GROUP" \
  --output table

Complete Example (Copy-Paste)

Replace the resource names and run all commands:

# 1. Set variables
RESOURCE_GROUP="ldfdev-rg"
AI_RESOURCE_NAME="ldfdev-ai"
SP_NAME="loan-defenders-docker-dev"
SUBSCRIPTION_ID=$(az account show --query id -o tsv)

# 2. Verify resources
az group show --name "$RESOURCE_GROUP"
az cognitiveservices account show --name "$AI_RESOURCE_NAME" --resource-group "$RESOURCE_GROUP"

# 3. Create service principal (save the output!)
az ad sp create-for-rbac \
  --name "$SP_NAME" \
  --role "Cognitive Services OpenAI User" \
  --scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$AI_RESOURCE_NAME" \
  --query "{appId: appId, password: password, tenant: tenant}" \
  -o json

# 4. Verify role assignment (replace CLIENT_ID with appId from step 3)
CLIENT_ID="<replace-with-appId>"
az role assignment list \
  --assignee "$CLIENT_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/$AI_RESOURCE_NAME" \
  --query "[].{Role:roleDefinitionName, Scope:scope}" \
  -o table

# 5. Add to .env file (replace with actual values from step 3)
echo "AZURE_TENANT_ID=<tenant>" >> .env
echo "AZURE_CLIENT_ID=<appId>" >> .env
echo "AZURE_CLIENT_SECRET=<password>" >> .env

Security Notes

Least Privilege: Service principal has read-only inference access ✅ Scoped: Limited to single AI Services resource only ⚠️ Rotate: Change credentials every 90 days minimum ⚠️ Production: Use Managed Identity instead of service principals ⚠️ Never Commit: .env is in .gitignore - keep credentials out of source control


Alternative: Use Automated Script

For a fully automated setup with validation and error handling:

./scripts/create-service-principal.sh

See: create-service-principal.sh


Last Updated: 2025-01-15