Skip to main content

Compare Azure resources with Terraform Enterprise workspaces

Project description

zephy

Azure TFE Resources Toolkit

Compare Azure resources deployed in a subscription against resources managed by Terraform Enterprise (TFE) workspaces. Identifies resource coverage gaps, unmanaged resources, and provides detailed resource inventory reports.

Features

  • Resource Discovery: Automatically discover all Azure resources in a subscription
  • TFE Integration: Connect to Terraform Enterprise to analyze workspace state files
  • Coverage Analysis: Identify which Azure resources are NOT managed by Terraform
  • Resource Matching: Advanced matching algorithm using Azure resource IDs
  • CSV Reports: Generate Excel-compatible CSV reports with UTF-8 BOM encoding
  • Caching: Optional file system caching for improved performance
  • Manual Mode: Fallback to manual Azure CLI commands when API access fails
  • Dry Run: Preview execution plan without making API calls

Installation

Requires Python 3.10 or higher.

pip install zephy

Now you can use it:

zephy --help

Install From Source

git clone https://github.com/henrybravo/zephy.git
cd zephy
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -e .

--or--

Install From Source Using uv (recommended)

about uv

git clone https://github.com/henrybravo/zephy.git
cd zephy
uv venv .venv
source .venv/bin/activate
uv pip install -r requirements.txt
uv pip install -e .

Quick Start

Basic Usage

# Login with az cli
az login

# Set environment variables
export TFE_TOKEN="your-tfe-token"
export AZURE_SUBSCRIPTION_ID="your-subscription-id"

# Run comparison
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID

Using Configuration File

# Create config.json (see config.example.json)
zephy --config config.json

Manual Azure CLI Mode

# Generate commands for manual execution

# change to your id:
export AZURE_SUBSCRIPTION_ID="00000000-0000-0000-0000-000000000000"

zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --azcli-manually

# Run the generated az commands manually, then:
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --azure-input-file azure_resources_$AZURE_SUBSCRIPTION_ID.json

Authentication

Azure Authentication

Uses DefaultAzureCredential with automatic fallback:

  1. Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
  2. Azure CLI (az login)
  3. Managed Identity (for CI/CD)

For service principal authentication, create a JSON file with the following format and use --azure-creds-file:

{
  "client_id": "your-service-principal-client-id",
  "client_secret": "your-service-principal-client-secret",
  "tenant_id": "your-azure-tenant-id",
  "subscription_id": "your-azure-subscription-id"
}

TFE Authentication

Set the TFE_TOKEN environment variable or use --tfe-token parameter.

For token from file, create a plain text file containing only the TFE API token and use --tfe-creds-file:

your-tfe-api-token-here

For self-hosted TFE instances with self-signed SSL certificates, use --no-tfe-ssl-verify to skip SSL certificate verification.

Configuration

Command Line Arguments

zephy --help

zephy help menu

Configuration File

Create a config.json file (see config.example.json for template):

{
  "tfe_base_url": "https://app.terraform.io/api/v2",
  "tfe_ssl_verify": true,
  "tfe_org": "your-tfe-organization",
  "azure_subscription": "your-azure-subscription-id",
  "workspaces": ["workspace-1", "workspace-2"],
  "resource_groups": ["prod-rg", "shared-rg"],
  "tfe_token": null,
  "tfe_creds_file": null,
  "azure_creds_file": null,
  "azcli_manually": false,
  "azure_input_file": null,
  "resource_mode": "primary",
  "cache_ttl": 60,
  "no_cache": false,
  "output_dir": "./reports",
  "save_resources": false,
  "logfile_dir": "./logs",
  "debug": false,
  "dry_run": false,
  "parallel": 10
}

Output

Generates five CSV files:

  1. resources_comparison_TIMESTAMP.csv: All resources with match status
  2. unmanaged_resources_TIMESTAMP.csv: Azure resources NOT in TFE
  3. multi_workspace_resources_TIMESTAMP.csv: Resources managed by multiple workspaces
  4. tfe_resources_inventory_TIMESTAMP.csv: Complete inventory of all TFE resources
  5. azure_resources_inventory_TIMESTAMP.csv: Complete inventory of all Azure resources

Generating Primary Resource Types

To generate the PRIMARY_RESOURCE_TYPES.json file with the correct Azure resource types:

# Ensure you're logged in to Azure CLI
az login

# Run the generation script
python generate_primary_resource_types.py

This script:

  • Queries Azure for all available resource types
  • Filters for primary infrastructure resources (VMs, databases, networks, etc.)
  • Excludes auxiliary/support resource types
  • Saves the filtered list to PRIMARY_RESOURCE_TYPES.json

Examples

Filter by Workspaces

zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --workspaces "prod-app,prod-db"

Detailed Resource Mode

zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --resource-mode detailed

Dry Run

zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --dry-run

Advanced Options

# Filter by resource groups
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --resource-groups "prod-rg,shared-rg"

# Use detailed resource mode and increase parallel requests
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --resource-mode detailed \
  --parallel 20

# Disable caching and set custom cache TTL
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --no-cache \
  --cache-ttl 120

# Use service principal credentials from file
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --azure-creds-file azure-creds.json

# Use TFE token from file
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --tfe-creds-file tfe-token.txt

# Skip SSL verification for self-hosted TFE
zephy \
  --tfe-org your-org \
  --azure-subscription $AZURE_SUBSCRIPTION_ID \
  --tfe-base-url https://your-self-hosted-tfe.com/api/v2 \
  --no-tfe-ssl-verify

Development

Setup Development Environment

pip install -e .[dev]

Run Tests

uv pip install pytest

pytest tests/ -v --cov=zephy --cov-report=html

Code Quality

black zephy/
flake8 zephy/
mypy zephy/

Security

  • Credentials are never logged in plain text
  • Sensitive data is redacted in logs
  • Config files with credentials trigger warnings
  • Use environment variables for credentials in production

Configure Azure App Registration for SDK Access

This guide assumes you already created an App Registration in Azure AD and have the following environment variables set:

export AZURE_CLIENT_ID="<your-azure-client-id>"
export AZURE_CLIENT_SECRET="<your-client-secret>"
export AZURE_TENANT_ID="<your-tenant-id>"
export AZURE_SUBSCRIPTION_ID="<your-azure-subscription-id>"
  1. Login with Azure CLI

Login with a user that has Owner or User Access Administrator on the subscription:

az login --tenant $AZURE_TENANT_ID
az account set --subscription $AZURE_SUBSCRIPTION_ID
  1. Assign RBAC Role to the Service Principal

The app registration (service principal) needs at least Reader role to list resources.

If you need deployment/management rights, use Contributor instead.

az role assignment create \
  --assignee $AZURE_CLIENT_ID \
  --role "Reader" \
  --scope /subscriptions/$AZURE_SUBSCRIPTION_ID

For Contributor role:

az role assignment create \
  --assignee $AZURE_CLIENT_ID \
  --role "Contributor" \
  --scope /subscriptions/$AZURE_SUBSCRIPTION_ID
  1. Verify the Role Assignment

Check if the role was applied correctly:

az role assignment list \
  --assignee $AZURE_CLIENT_ID \
  --scope /subscriptions/$AZURE_SUBSCRIPTION_ID \
  --output table
  1. Refresh Tokens if Access Was Just Granted

If you get AuthorizationFailed after role assignment:

az account clear

Then restart your app to pick up fresh tokens.

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zephy-1.0.5.tar.gz (43.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zephy-1.0.5-py3-none-any.whl (45.1 kB view details)

Uploaded Python 3

File details

Details for the file zephy-1.0.5.tar.gz.

File metadata

  • Download URL: zephy-1.0.5.tar.gz
  • Upload date:
  • Size: 43.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for zephy-1.0.5.tar.gz
Algorithm Hash digest
SHA256 9d15cdf62ed19a1cf3a24f6f21af46462bad78a371968b039e2e09e5d699ed2e
MD5 da656d06177a2d421b09b790345807ba
BLAKE2b-256 cb6aea230774ed4e53cd253ee8aa04b7ea2c585221539491fac3b9e42ddf2dd1

See more details on using hashes here.

File details

Details for the file zephy-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: zephy-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 45.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for zephy-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 b915f9e622717d7ff057c46694b22f8d4dbd2391f4abadd5219a6fa140498bfc
MD5 e828ef936c003c5fc4a8e42983e92502
BLAKE2b-256 d4ed4953cf1ef93a5ed975dd84f77a343fa8c05c561ca0b05456d9f7e3957002

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page