A Bubble Tea terminal UI that guides you through creating Azure Policy exemptions with the Azure CLI.
Download the latest binary for your platform from GitHub Releases.
brew install Lukas-Klein/tap/azexempt
OS=$(uname -s | tr '[:upper:]' '[:lower:]') # darwin / linux
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
mkdir -p ~/.local/bin
curl -sL "https://github.com/Lukas-Klein/azexempt/releases/latest/download/azexempt_${OS}_${ARCH}.tar.gz" \
| tar xz -C ~/.local/bin azexempt
chmod +x ~/.local/bin/azexempt$arch = if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { "x86_64" } else { "arm64" }
$zip = "azexempt_windows_${arch}.zip"
$dest = "$env:LOCALAPPDATA\Programs\azexempt"
Invoke-WebRequest `
"https://github.com/Lukas-Klein/azexempt/releases/latest/download/$zip" `
-OutFile "$env:TEMP\$zip"
Expand-Archive -Path "$env:TEMP\$zip" -DestinationPath $dest -Force
Remove-Item "$env:TEMP\$zip"
# Add to PATH for the current user (persistent across sessions)
$path = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($path -notlike "*$dest*") {
[Environment]::SetEnvironmentVariable('Path', "$path;$dest", 'User')
$env:Path += ";$dest"
}Restart your terminal, then run azexempt.
Requires Go 1.21 or later:
go install github.com/Lukas-Klein/azexempt@latest- The Azure CLI available on your
PATH - Permission to list subscriptions, read policy definitions and create exemptions
- Authentication: Ensures you are logged into Azure (
az loginis started automatically when needed). - Subscription Selection: Retrieves all subscriptions you have access to and lets you pick one.
- Assignment Selection: Lists all policy assignments in the selected subscription.
- Definition Selection: If the assignment is a Policy Set (Initiative), allows you to exempt the entire assignment or specific definitions within it.
- Scope Selection: Choose to apply the exemption at the Subscription level or select a specific Resource Group.
- Details: Prompts for a tracking ticket number and requester names.
- Expiration: Optionally set an expiration date for the exemption.
- Creation: Calls
az policy exemption createwith the collected data and prints the Azure CLI response.
# Run directly
go run main.go
# Or build and run
go build -o azexempt main.go
./azexemptFollow the on-screen instructions. Use ↑/↓ to navigate lists, Space to toggle selections, and Enter to confirm. Press q at any time to quit.
| Key | Action |
|---|---|
↑/↓ or k/j |
Navigate lists |
Enter |
Confirm selection |
Space |
Toggle selection (in multi-select lists) |
Backspace |
Go back to previous step |
q |
Quit the application |
| Type characters | Search/filter subscriptions |
Esc |
Clear search |
The CLI supports an optional configuration file to customize behavior. The config file is searched in the following locations (first match wins):
./config.yaml(current directory)./config.yml~/.azexempt/config.yaml~/.azexempt/config.yml$XDG_CONFIG_HOME/azexempt/config.yaml(or~/.config/azexempt/config.yaml)
Legacy azure-exemption-cli config directories are also supported for upgrades.
See config.yaml.example for a sample configuration file.
You can configure a list of policy definitions that cannot be exempted. This is useful for enforcing compliance by preventing exemptions on critical security or governance policies.
blocked_policy_definition_ids:
- /providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4cHow it works:
- The blocked list uses policy definition IDs (not assignment IDs)
- A single policy definition can be used by multiple policy assignments across your environment
- When you block a policy definition, all assignments using that definition will be blocked
- Blocked assignments appear greyed out with a
[-]marker and[blocked]label - Attempting to select a blocked assignment shows an error message
Example: If you block the "Inherit a tag from the subscription" policy definition, any policy assignment that uses this definition will be blocked - whether it's a standalone assignment or part of a policy set (initiative).
Finding Policy Definition IDs:
You can find policy definition IDs using the Azure CLI:
# List all policy definitions
az policy definition list --query "[].{name:name, displayName:displayName, id:id}" -o table
# Find a specific policy by display name
az policy definition list --query "[?contains(displayName, 'Inherit a tag')].{displayName:displayName, id:id}" -o table
# Get the definition ID from a policy assignment
az policy assignment show --name <assignment-name> --query "policyDefinitionId" -o tsvThe project follows a standard Go project layout:
main.go: Application entry point./azure: Azure CLI interaction logic and types./tui: Bubble Tea UI model, views, and update logic./config: Configuration loading and parsing.