This project demonstrates Azure resource tagging inheritance issues and provides solutions using Pulumi, Azure Resource Graph, and Azure Policy.
- Azure Resource Tagging Inheritance POC
The POC creates an environment where Virtual Machines have proper tags but their attached disks don't inherit those tags, demonstrating a common Azure governance challenge. The project then provides automated solutions to identify and remediate these tagging gaps using Azure Policy implementation for automated tag governance and compliance enforcement. The solution includes custom Azure Policies that audit untagged disks and enforce required tags on VMs, providing a comprehensive approach to tag inheritance and governance.
Before getting started, ensure you have the following tools installed:
- Azure CLI
- Pulumi CLI
- Node.js (v14 or later)
- npm (comes with Node.js)
git clone <repository-url>
cd poc-tag-inheritance
Login to Azure CLI:
az login
Verify your subscription:
az account show
If you need to switch subscriptions:
az account set --subscription "your-subscription-id"
Run the setup script to create the Azure Storage backend and initialize the Pulumi project:
./setup-pulumi-backend.sh
This script will:
- β Create a resource group for Pulumi state storage
- β Create an Azure Storage Account with proper security settings
- β Create a blob container for state files
- β Configure Pulumi to use the Azure Storage backend
- β Initialize the Pulumi project with TypeScript
After running the setup script, configure your Pulumi stack with the required settings:
# Set Azure location
pulumi config set azure-native:location "East US"
# Set your Azure subscription ID (replace with your actual subscription ID)
pulumi config set azure-native:subscriptionId "your-subscription-id"
# Set project-specific configuration
pulumi config set project:name "poc-tag-inheritance"
pulumi config set project:environment "POC"
pulumi config set project:owner "PLACEHOLDER-Team"
# Set VM credentials configuration
pulumi config set vm:adminUsername "azureuser"
pulumi config set vm:adminPassword "P@ssw0rd123!" --secret
pulumi config set vm:disablePasswordAuthentication "false"
To get your Azure subscription ID:
az account show --query id -o tsv
If you need to reconnect to the project later (e.g., on a new machine or after logging out), follow these steps:
az login
You'll need the storage account name from your initial setup. Check the setup script output or find it in Azure Portal:
export AZURE_STORAGE_ACCOUNT="stpulumitagpoc<timestamp>"
export AZURE_STORAGE_KEY="<your-storage-key>"
To get the storage key:
# Replace with your actual resource group and storage account names
az storage account keys list \
--resource-group "rg-pulumi-state-poc-tag-inheritance" \
--account-name "stpulumitagpoc<timestamp>" \
--query '[0].value' -o tsv
pulumi login azblob://pulumi-state
pulumi stack select dev
For convenience, you can use the provided reconnect script that automates the above steps:
source ./reconnect-to-project.sh
Note: Use source
to ensure environment variables persist in your current shell session.
This script will automatically:
- Find your storage account
- Set the required environment variables
- Login to the Pulumi backend
- Select the dev stack
Check that everything is configured correctly:
# Check Pulumi configuration
pulumi config
# Verify all required config values are set
pulumi config get azure-native:location
pulumi config get azure-native:subscriptionId
pulumi config get project:name
pulumi config get project:environment
pulumi config get project:owner
# Verify VM configuration values are set
pulumi config get vm:adminUsername
pulumi config get vm:adminPassword
pulumi config get vm:disablePasswordAuthentication
# Check current stack
pulumi stack
# Preview infrastructure (without deploying)
pulumi preview
The project creates a complete environment to demonstrate the tagging inheritance problem:
- Resource Group:
poc-rg
with standard organizational tags - Virtual Network:
poc-vnet
with subnet and network security group - Virtual Machines: Two VMs (
poc-vm1
,poc-vm2
) with comprehensive tags - Data Disks: Untagged disks attached to the VMs (demonstrating the problem)
- Network Resources: Public IPs, NICs, and NSG with proper tagging
- Azure Policies: Custom policy definitions for tag governance
- Tag Inheritance Policy: Audits disks without inherited tags
- Required Tags Policy: Enforces required tags on VMs
- Policy Initiative: Comprehensive tagging governance framework
- Managed Identity: For policy execution with appropriate permissions
All properly tagged resources include:
Environment
: "POC"Project
: "TaggingInheritance"Owner
: "PLACEHOLDER-Team"CostCenter
: "IT-001"Role
: "WebServer" or "DatabaseServer"Application
: "Frontend" or "Backend"
The data disks (poc-vm1-data-disk
, poc-vm2-data-disk
) are intentionally created without tags to demonstrate the inheritance problem that this POC aims to solve.
Use the automated deployment script:
./deploy-infrastructure.sh
This script will:
- β Check Azure and Pulumi prerequisites
- β Deploy the complete POC infrastructure
- β Display deployment summary with resource information
- β Provide next steps and useful commands
Run the validation script to see the tagging inheritance issue:
./validate-tagging-problem.sh
This script will:
- π List all resources in the resource group
- π·οΈ Show VM tagging status (should be comprehensive)
- πΎ Show disk tagging status (should be missing tags)
- π Use Azure Resource Graph for detailed analysis
- π Provide compliance statistics
After deployment, validate that the Azure Policy implementation is working correctly:
./validate-policy-implementation.sh
This script will:
- π Check that custom policy definitions are deployed
- π Verify policy initiative (policy set) is created
- β Confirm policy assignments are active at resource group scope
- π Validate managed identity and role assignments
- π Show current policy compliance status
- π·οΈ Display current resource tagging state
- π Provide policy enforcement summary and next steps
The validation will confirm:
- β Tag Inheritance Policy: Audits disks without inherited tags
- β Required Tags Policy: Enforces required tags on VMs
- β Policy Initiative: Comprehensive tagging governance
- β Policy Assignments: Active enforcement at resource group scope
- β Managed Identity: Proper permissions for policy execution
After deployment and validation, you should see:
- β VMs with comprehensive tags
- β Data disks without any tags (demonstrating the problem)
- β Azure Policies deployed and actively monitoring compliance
- π Policy compliance reports showing untagged resources
- π Clear demonstration of the tagging inheritance problem and governance solution
Edit index.ts
to modify your infrastructure:
import * as azure from "@pulumi/azure-native";
// Your infrastructure code here
pulumi preview
pulumi up
# or use the deployment script
./deploy-infrastructure.sh
pulumi stack output
# Validate the tagging inheritance problem
./validate-tagging-problem.sh
# Validate Azure Policy implementation
./validate-policy-implementation.sh
If you have policies with modify
effect that need to fix existing non-compliant resources:
# Create remediation task for tag inheritance policy
./create-remediation-task.sh -p tag-inheritance-assignment -r <your-resource-group> -w
# Or use the resource group from your stack output
RESOURCE_GROUP=$(pulumi stack output resourceGroupName)
./create-remediation-task.sh -p tag-inheritance-assignment -r $RESOURCE_GROUP -w -v
pulumi destroy
After deploying the POC infrastructure, use Azure Resource Graph to analyze tagging compliance and identify gaps.
Before running the full analysis, test that the queries work correctly:
./test-queries.sh
This will validate all KQL queries and show sample results.
Execute the full resource tagging analysis:
./analyze-resource-tagging.sh
This script will:
- π Find VMs and their attached disks
- π·οΈ Identify untagged disks with tagged parent VMs
- π Analyze all POC resources and their tagging status
- π Generate timestamped reports in
analysis-results/
directory - π Provide compliance statistics and recommendations
The analysis generates several output files:
# View the summary report
cat analysis-results/summary-report_<timestamp>.md
# Check untagged data disks
cat analysis-results/untagged-data-disks_<timestamp>.json
# Review comprehensive analysis
cat analysis-results/comprehensive-analysis_<timestamp>.json
The project includes several KQL queries in the queries/
directory:
find-vms-and-disks.kql
: Discovers VMs and their attached disksfind-untagged-disks.kql
: Identifies untagged disks with tagged parent VMsfind-untagged-data-disks.kql
: Finds untagged data disks in POC environmentcomprehensive-tagging-analysis.kql
: Analyzes all POC resources and tagging status
You can also run individual queries manually:
# Find untagged data disks
az graph query -q "$(cat queries/find-untagged-data-disks.kql)" --output table
# Get detailed JSON output
az graph query -q "$(cat queries/find-untagged-data-disks.kql)" --output json
# Analyze all POC resources
az graph query -q "$(cat queries/comprehensive-tagging-analysis.kql)" --output table
The analysis will typically show:
- β VMs: Properly tagged with 6 tags each
- β OS Disks: Inherit tags from VM during creation
- β Data Disks: Missing tags (demonstrating the inheritance problem)
- β Network Resources: Properly tagged
The POC includes a comprehensive Azure Policy implementation to address tag inheritance and governance challenges.
The implementation includes:
-
Tag Inheritance Policy (
audit
effect)- Identifies disks attached to VMs that don't have inherited tags
- Audits resources for compliance reporting
- Helps identify tagging gaps for manual remediation
-
Required Tags Policy (
deny
effect)- Enforces that all VMs must have required tags
- Prevents creation of non-compliant resources
- Ensures consistent tagging from resource creation
-
Policy Initiative (Policy Set)
- Combines both policies into a comprehensive governance framework
- Provides centralized management and assignment
- Enables consistent policy enforcement across resources
After deployment, validate the policy implementation:
./validate-policy-implementation.sh
Monitor policy compliance through:
- Azure Portal: Policy > Compliance dashboard
- CLI Commands:
az policy state list --resource-group <rg-name>
- Compliance Reports: Generated by the validation script
- Audit Effect: Identifies non-compliant resources without blocking operations
- Deny Effect: Prevents creation of non-compliant resources
Note: This POC does not implement automatic tag remediation (modify effect). The policies focus on identification and prevention rather than automatic correction.
When Azure Policies with modify
effect are deployed, they don't automatically fix existing non-compliant resources. You need to create remediation tasks to apply the policy changes to existing resources.
Use the provided script to create remediation tasks:
# Basic usage - create remediation for tag inheritance policy
./create-remediation-task.sh -p tag-inheritance-assignment -r poc-rgxxx
# With custom name and wait for completion
./create-remediation-task.sh -p tag-inheritance-assignment -r poc-rgxxx -n my-remediation-task -w
# Verbose output with waiting
./create-remediation-task.sh --policy-assignment tag-inheritance-assignment --resource-group poc-rgxxx --wait --verbose
The create-remediation-task.sh
script provides:
- β Validation: Checks Azure CLI login, resource group, and policy assignment existence
- π Pre-check: Identifies non-compliant resources before creating remediation
- π·οΈ Auto-naming: Generates timestamped remediation names if not provided
- β±οΈ Wait Option: Optionally waits for remediation completion (up to 5 minutes)
- π Status Monitoring: Shows remediation progress and final status
- π― Flexible Options: Supports custom scopes, filters, and verbose output
Option | Description | Required |
---|---|---|
-p, --policy-assignment |
Policy assignment name | β Yes |
-r, --resource-group |
Resource group name | β Yes |
-n, --name |
Custom remediation name | β No (auto-generated) |
-s, --scope |
Custom scope for remediation | β No |
-f, --filter |
Resource discovery filter | β No |
-w, --wait |
Wait for completion | β No |
-v, --verbose |
Verbose output | β No |
-h, --help |
Show help message | β No |
You can also create remediation tasks manually:
# Create remediation task
az policy remediation create \
--name "tag-inheritance-remediation-$(date +%Y%m%d-%H%M%S)" \
--policy-assignment tag-inheritance-assignment \
--resource-group poc-rgxxx
# Check remediation status
az policy remediation show \
--name "your-remediation-name" \
--resource-group poc-rgxxx
# List all remediation tasks
az policy remediation list --resource-group poc-rgxxx --output table
After running remediation:
- Check Deployment Status: Look for
successfulDeployments
count - Verify Resource Tags: Confirm tags have been applied to previously untagged resources
- Monitor Compliance: Use policy compliance reports to verify improvements
If the Azure Policy approach (policy + remediation) doesn't work for your environment, use the automated tagging script as an alternative:
# Test what would be changed (dry run)
./tag-inheritance-script.sh --subscription YOUR_SUBSCRIPTION_ID --dry-run
# Apply tag inheritance to untagged disks
./tag-inheritance-script.sh --subscription YOUR_SUBSCRIPTION_ID
This script directly applies VM tags to untagged disks without requiring Azure Policy. See docs/phase3-automated-tagging-solution.md
for detailed documentation.
For production implementation, consider:
- Expand Scope: Apply policies at subscription or management group level
- Add Remediation: Implement
modify
effect policies for automatic tag inheritance - Custom Logic: Develop more sophisticated tag inheritance rules
- Monitoring: Set up alerts for policy compliance violations
- Exception Handling: Define exemptions for special cases
- Automated Remediation: Schedule regular remediation tasks for ongoing compliance
- Remediation Workflows: Integrate remediation into CI/CD pipelines or Azure Automation
README.md
Provided by Tidal [email protected]