Skip to main content

Compare Azure resources with Terraform Enterprise workspaces

Project description

zephy

PyPI version Python Version License: MIT PyPI Downloads Downloads Code style: black

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 \
  --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
  • TFE workspace tags are only available for commercial TFE workspaces
  • Azure resource groups tags only when using the azure api and not the Manual Azure CLI Mode

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_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.1.2.tar.gz (396.8 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.1.2-py3-none-any.whl (47.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for zephy-1.1.2.tar.gz
Algorithm Hash digest
SHA256 d52e84ab6831d1c5e8ba4c2b49b01413579a1338b97370820018934b2794cfe6
MD5 2481067d27e24905ee7ef5eea5beb452
BLAKE2b-256 f7f628815305442ba05100e9e12a49d4562af2bb18e2fed703a888af8a8f489f

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for zephy-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c27189a92520f83fecde0ea14f0c4537097e4d865aa41ff549155fecd7ad6d81
MD5 1deff7cb91d6b269a75d732a04316e14
BLAKE2b-256 1a97912c6d2474cf5789befd7d2e36dee6b8628b76e5e33583d21915b0a2c4eb

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