Azure Authentication
This guide shows you how to configure Azure authentication using the native atmos auth system.
Overview​
Atmos Auth provides native Azure authentication that works identically to az login, with support for:
- Device Code Flow (browser-based authentication for users)
- OIDC (workload identity for CI/CD pipelines)
- Service Principals (client credentials for automation)
All authentication methods write credentials to the Azure CLI MSAL cache (~/.azure/msal_token_cache.json), ensuring full compatibility with Terraform's Azure providers (azurerm, azuread, azapi).
Quick Start​
Basic Azure Device Code Authentication​
The simplest Azure authentication uses device code flow for interactive user login:
auth:
providers:
azure-dev:
kind: azure/device-code
tenant_id: "12345678-1234-1234-1234-123456789012"
subscription_id: "87654321-4321-4321-4321-210987654321"
location: "eastus"
identities:
azure-dev-subscription:
default: true
kind: azure/subscription
via:
provider: azure-dev
principal:
subscription_id: "87654321-4321-4321-4321-210987654321"
location: "eastus"
Authenticate:
atmos auth login
This will:
- Display a device code and verification URL
- Open your browser to https://microsoft.com/devicelogin
- Prompt you to enter the code and sign in
- Cache credentials for all Azure providers (azurerm, azuread, azapi)
Authentication Methods​
Device Code Flow (Interactive)​
Best for: Developer workstations, interactive sessions
Device code flow provides browser-based authentication with full MFA support:
auth:
providers:
azure-interactive:
kind: azure/device-code
tenant_id: "YOUR_TENANT_ID"
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "eastus"
identities:
azure-dev:
kind: azure/subscription
via:
provider: azure-interactive
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "eastus"
How it works:
- Atmos displays a device code (e.g., "WDDD-HRQV")
- Browser opens to Microsoft's device login page
- You enter the code and sign in (with MFA if configured)
- Atmos receives 3 token scopes:
https://management.azure.com/.default(Azure Resource Manager)https://graph.microsoft.com/.default(Azure AD operations)https://vault.azure.net/.default(Azure KeyVault operations)
Usage:
# Authenticate interactively
atmos auth login --identity azure-dev
# Use with Terraform
atmos terraform plan my-component -s my-stack
OIDC (Workload Identity for CI/CD)​
Best for: GitHub Actions, GitLab CI, Azure DevOps pipelines
OIDC enables passwordless authentication using federated credentials:
auth:
providers:
azure-oidc:
kind: azure/oidc
tenant_id: "YOUR_TENANT_ID"
client_id: "YOUR_APP_CLIENT_ID"
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "eastus"
identities:
azure-ci:
kind: azure/subscription
via:
provider: azure-oidc
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
Setup Requirements:
- Create an Azure AD App Registration
- Configure federated credentials for your CI/CD platform
- Grant app appropriate Azure RBAC roles
- Set environment variables in your pipeline:
AZURE_CLIENT_ID="YOUR_APP_CLIENT_ID"
AZURE_TENANT_ID="YOUR_TENANT_ID"
AZURE_SUBSCRIPTION_ID="YOUR_SUBSCRIPTION_ID"
Example GitHub Actions workflow:
name: Deploy Infrastructure
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Atmos
uses: cloudposse/github-action-setup-atmos@v2
- name: Authenticate to Azure
run: atmos auth login --identity azure-ci
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Deploy
run: atmos terraform apply my-component -s prod
Service Principal (Client Credentials)​
Best for: Automation, service accounts, long-running processes
Service principals use client ID and secret for non-interactive authentication:
auth:
providers:
azure-service-principal:
kind: azure/service-principal
tenant_id: "YOUR_TENANT_ID"
client_id: "YOUR_SERVICE_PRINCIPAL_CLIENT_ID"
client_secret: "YOUR_CLIENT_SECRET" # Store securely!
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "eastus"
identities:
azure-automation:
kind: azure/subscription
via:
provider: azure-service-principal
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
Security Best Practices:
- Never commit secrets to version control
- Use environment variables:
export AZURE_CLIENT_SECRET="..." - Or use Atmos's secrets integration:
client_secret: "{{ (store.get \"secret/azure/client-secret\").data.value }}"
Usage:
# Set secret via environment variable
export AZURE_CLIENT_SECRET="your-secret-here"
# Authenticate
atmos auth login --identity azure-automation
# Run Terraform
atmos terraform apply my-component -s prod
Multi-Subscription Workflows​
Atmos makes it easy to work with multiple Azure subscriptions:
auth:
providers:
azure-main:
kind: azure/device-code
tenant_id: "YOUR_TENANT_ID"
subscription_id: "DEV_SUBSCRIPTION_ID"
location: "eastus"
identities:
azure-dev:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "DEV_SUBSCRIPTION_ID"
location: "eastus"
azure-staging:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "STAGING_SUBSCRIPTION_ID"
location: "westus"
azure-prod:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "PROD_SUBSCRIPTION_ID"
location: "eastus2"
Switch between subscriptions:
# Deploy to dev
atmos terraform apply my-component -s dev --identity azure-dev
# Deploy to staging
atmos terraform apply my-component -s staging --identity azure-staging
# Deploy to prod
atmos terraform apply my-component -s prod --identity azure-prod
Terraform Provider Compatibility​
Atmos Azure authentication works seamlessly with all Terraform Azure providers:
azurerm Provider​
Atmos sets ARM_USE_CLI=true, enabling the azurerm provider to use Azure CLI credentials:
provider "azurerm" {
features {}
# Atmos automatically sets:
# - ARM_USE_CLI=true
# - ARM_SUBSCRIPTION_ID
# - ARM_TENANT_ID
# - ARM_LOCATION
}
resource "azurerm_key_vault" "example" {
name = "my-keyvault"
location = "eastus"
tenant_id = data.azurerm_client_config.current.tenant_id
# KeyVault operations work because Atmos provides KeyVault token scope
}
azuread Provider​
The azuread provider automatically uses Graph API tokens from Atmos:
provider "azuread" {
# Atmos provides Graph API token via ARM_USE_CLI
}
resource "azuread_group" "example" {
display_name = "My Group"
security_enabled = true
}
azapi Provider​
The azapi provider also works with Azure CLI authentication:
provider "azapi" {
# Atmos authentication "just works"
}
resource "azapi_resource" "example" {
type = "Microsoft.Network/virtualNetworks@2021-02-01"
name = "my-vnet"
parent_id = azurerm_resource_group.example.id
# ...
}
Token Scopes​
Atmos Azure authentication provides all three token scopes required for full Azure functionality:
| Token Scope | Used By | Purpose |
|---|---|---|
https://management.azure.com/.default | azurerm, azapi | Azure Resource Manager operations |
https://graph.microsoft.com/.default | azuread | Azure Active Directory operations |
https://vault.azure.net/.default | azurerm | Azure KeyVault operations |
This matches exactly what az login provides, ensuring 100% compatibility.
Authentication Flow​
When you run atmos auth login:
- Provider Authentication: Atmos authenticates using configured method (device code/OIDC/service principal)
- Token Acquisition: Requests all 3 token scopes from Azure AD
- MSAL Cache Update: Writes tokens to
~/.azure/msal_token_cache.json - Profile Update: Updates
~/.azure/azureProfile.jsonwith subscription info - Environment Setup: Sets ARM_* environment variables for Terraform
- Credential Storage: Caches credentials in system keyring for reuse
Common Patterns​
Pattern 1: Developer + CI/CD​
Use device code for developers, OIDC for pipelines:
auth:
providers:
azure-dev-interactive:
kind: azure/device-code
tenant_id: "YOUR_TENANT_ID"
subscription_id: "DEV_SUBSCRIPTION_ID"
azure-ci:
kind: azure/oidc
tenant_id: "YOUR_TENANT_ID"
client_id: "YOUR_APP_CLIENT_ID"
subscription_id: "PROD_SUBSCRIPTION_ID"
identities:
azure-dev:
default: true # Default for developers
kind: azure/subscription
via:
provider: azure-dev-interactive
principal:
subscription_id: "DEV_SUBSCRIPTION_ID"
azure-prod-ci:
kind: azure/subscription
via:
provider: azure-ci
principal:
subscription_id: "PROD_SUBSCRIPTION_ID"
Pattern 2: Multi-Region Deployment​
Deploy to multiple Azure regions:
auth:
providers:
azure-main:
kind: azure/device-code
tenant_id: "YOUR_TENANT_ID"
subscription_id: "YOUR_SUBSCRIPTION_ID"
identities:
azure-eastus:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "eastus"
azure-westus:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "westus"
azure-westeurope:
kind: azure/subscription
via:
provider: azure-main
principal:
subscription_id: "YOUR_SUBSCRIPTION_ID"
location: "westeurope"
Troubleshooting​
Token Expiration​
Azure tokens typically expire after 1 hour. Atmos automatically caches and reuses valid tokens:
# Check current authentication status
atmos auth whoami
# Re-authenticate if expired
atmos auth login
Missing Token Scopes​
If you see errors about missing permissions, ensure all 3 token scopes are configured:
# Check MSAL cache contents
cat ~/.azure/msal_token_cache.json | jq '.AccessToken | keys[]'
# Should see entries for:
# - management.azure.com
# - graph.microsoft.com
# - vault.azure.net
Provider Not Found​
Ensure your Terraform providers are configured to use ARM_USE_CLI:
# Check environment
atmos auth env --identity azure-dev
# Should show:
# ARM_USE_CLI=true
# ARM_SUBSCRIPTION_ID=...
# ARM_TENANT_ID=...
Security Considerations​
Credential Storage​
- Credentials are stored in your system keyring (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows)
- Tokens are also cached in
~/.azure/msal_token_cache.jsonfor Terraform provider compatibility - Both storages are secured by your operating system
Least Privilege​
Grant identities only the permissions they need:
# Example: Grant Contributor role to a subscription
az role assignment create \
--assignee YOUR_APP_CLIENT_ID \
--role Contributor \
--scope /subscriptions/YOUR_SUBSCRIPTION_ID
Audit Logging​
Enable Azure AD sign-in logs to audit authentication:
- Go to Azure Portal → Azure Active Directory → Monitoring → Sign-in logs
- Filter by "Application" to see Atmos authentications
Migration from az login​
Already using az login? Atmos authentication is a drop-in replacement:
Before (using az login):
az login
az account set --subscription "YOUR_SUBSCRIPTION_ID"
terraform apply
After (using Atmos):
atmos auth login --identity azure-dev
atmos terraform apply my-component -s my-stack
Both write to the same Azure CLI credential files, so your Terraform code doesn't need any changes.
Next Steps​
- Learn more about auth commands
- Configure authentication for workflows
- Set up authentication for custom commands
- Explore auth environment variables