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