Skip to content

[design-spec] azure-nsg-desired-state-drift #72

@rw-codebundle-agent

Description

@rw-codebundle-agent

CodeBundle Design Spec — azure-nsg-desired-state-drift

Parent: codecollection-registry#49 (Firewall & NSG Integrity)

codebundle_name: "azure-nsg-desired-state-drift"
target_collection: "rw-cli-codecollection"
display_name: "Azure NSG Desired-State Drift Detection"
author: "rw-codebundle-agent"

purpose: |
Detect out-of-band changes to Network Security Groups by comparing live NSG
rules and associations against a repo-managed baseline (declared desired state).
Surfaces drift that indicates manual portal/CLI edits or unauthorized changes
outside your IaC pipeline.

tasks:

  • name: "Export Live NSG Rules for Comparison"
    description: "For each NSG in scope, export security rules and default rules in stable JSON (subscription, RG, NSG name, rule set) for diffing."
    script_name: "nsg-export-live-rules.sh"
    expected_issue_severity: [2, 3]
    access_level: "read-only"
    data_type: "logs-config"

  • name: "Load and Normalize Baseline NSG Definition"
    description: "Read baseline from user-supplied path (JSON export, Terraform plan artifact, or directory of per-NSG files) and normalize to the same schema as live export."
    script_name: "nsg-load-baseline.sh"
    expected_issue_severity: [2]
    access_level: "read-only"
    data_type: "logs-config"

  • name: "Diff Live vs Baseline and Report Drift"
    description: "Compare normalized live vs baseline; flag added/removed/changed rules (priority, direction, access, protocol, ports, source/destination). Emit actionable issue per drift category."
    script_name: "nsg-diff-desired-state.sh"
    expected_issue_severity: [3, 4]
    access_level: "read-only"
    data_type: "logs-config"

  • name: "Validate Subnet and NIC NSG Associations"
    description: "Cross-check which subnets/NICs attach to each NSG; optionally compare association list to baseline to catch attachment drift."
    script_name: "nsg-association-audit.sh"
    expected_issue_severity: [2, 3]
    access_level: "read-only"
    data_type: "logs-config"

  • name: "Summarize Drift Scope for Operators"
    description: "Aggregate drift counts by subscription/RG, link to Azure Portal resource URLs, and suggest rollback via pipeline or IaC reconcile."
    script_name: "nsg-drift-summary.sh"
    expected_issue_severity: [1, 2]
    access_level: "read-only"
    data_type: "logs-config"

scope:
level: "ResourceGroup"
qualifiers:
- AZURE_SUBSCRIPTION_ID
- AZURE_RESOURCE_GROUP
- NSG_NAMES
iteration_pattern: |
One SLX per discovered NSG (or per user-provided NSG list) within the
subscription/RG qualifiers. Loop variable: NSG name and resource ID.

resource_types:

  • "microsoft_network_network_security_groups"
    generation_strategy: |
    Generation rules: platform azure; resourceTypes microsoft.network/networkSecurityGroups
    (or equivalent RunWhen resource type for NSGs). Match by name pattern within
    configured resource groups. Qualifiers: subscription_id, resource_group, nsg name.

env_vars:

  • name: AZURE_SUBSCRIPTION_ID
    description: "Azure subscription ID for scope"
    required: true

  • name: AZURE_RESOURCE_GROUP
    description: "Resource group containing NSGs (or empty with discovery across listed RGs)"
    required: false
    default: ""

  • name: NSG_NAMES
    description: "Comma-separated NSG names, or 'All' for all NSGs in the resource group"
    required: false
    default: "All"

  • name: BASELINE_PATH
    description: "Path or URI to baseline JSON (or directory of baseline files) matching export schema"
    required: true

  • name: BASELINE_FORMAT
    description: "json-bundle | per-nsg-dir | terraform-show (optional future)"
    required: false
    default: "json-bundle"

secrets:

  • name: azure_credentials
    description: "Service principal for Azure Resource Manager read access to NSGs and associations"
    format: |
    JSON: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID

platform:
name: "azure"
cli_tools:
- "az network nsg"
- "az network vnet subnet"
- "az network nic"
- "jq"
- "diff"
auth_methods:
- "Service Principal (azure_credentials)"
api_docs: "https://learn.microsoft.com/en-us/rest/api/virtual-network/network-security-groups/"

related_bundles:

  • name: "azure-aks-triage"
    relationship: "complements"
    notes: "AKS triage lists subnet NSG rules in passing; this bundle is dedicated to drift vs baseline across NSGs."

  • name: "azure-network-security-activity-audit"
    relationship: "complements"
    notes: "Activity audit explains who changed rules; drift bundle shows what differs from desired state."

test_scenarios:

  • name: "nsg_matches_baseline"
    description: "Live export identical to baseline"
    expected_issues: 0

  • name: "manual_rule_added"
    description: "Extra allow rule added in portal not in baseline"
    expected_issues: 2
    expected_severities: [3, 3]

notes: |
Baseline source is customer-specific: many teams store Terraform in Git and can
export terraform show -json or use az network nsg show checked into a config
repo. The bundle should document one supported canonical JSON shape and allow
optional jq transforms for team-specific exports. Effective security rules
(including Azure defaults) may need to be filtered so only customer-managed rule
blocks are compared—parameterize rule name prefixes or ignore lists. Read-only
RBAC: Reader on subscription/RG plus Microsoft.Network/*/read.

Metadata

Metadata

Assignees

No one assigned

    Labels

    azurecompletedAgent work completeddesign-specArchitect has produced a design specnew-codebundleScoped issue for SRE to implement a new CodeBundle

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions