DEV Community

Abhishek Kadlii
Abhishek Kadlii

Posted on

Stopping Rogue Deployments: How I Programmed Azure API Guardrails to Protect the Cloud Wallet

Every cloud architect knows the sudden wave of anxiety that comes with opening a billing dashboard and seeing an unexpected cost spike. In large enterprise environments, these spikes rarely happen due to malicious attacksโ€”they happen due to human error. A junior developer spinning up a high-performance compute or GPU node for a minor test case and forgetting to deprovision it over the weekend can vaporize a sandbox budget in hours.

Instead of relying on warning emails, training manuals, or reactive cleanup scripts, I stepped up as a DevSecOps engineer to solve this problem at the source. I programmed the Azure Resource Manager (ARM) API gateway itself to automatically intercept and decline unauthorized resource allocations using Azure Policy and Custom RBAC Least-Privilege roles.


๐Ÿฐ The Analogy: The Bouncing Corporate Credit Card

To understand this architecture, look at how corporate spending is managed in the physical world:

  • The Weak Setup (The Honor System): Handing a corporate credit card with a โ‚น5,00,000 limit to an employee, giving them a policy handbook, and hoping they do not buy a luxury watch. If they make a mistake, the money is already gone, and you are left doing damage control.
  • The Guardrail Setup (The Terminal Lock): Programming the payment terminal directly at the cash register. If the employee attempts to swipe the card for anything outside approved inventory codes or locations, the transaction is forcefully declined on the spot before a single rupee leaves the corporate account.
                               โ”Œโ”€โ”€โ–บ [ Approved SKU: B-Series Only ] โ”€โ”€โ–บ โœ… ALLOWED (Passes Gate)
                               โ”‚
[ Deployment Request ] โ”€โ”€โ–บ [ Azure Policy ARM Gate ]
                               โ”‚
                               โ””โ”€โ”€โ–บ [ Prohibited SKU: D-Series Node ] โ”€โ”€โ–บ โŒ DENIED (Declined at Register)
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ The Step-by-Step Command-Line Execution Blueprint

To demonstrate a production-grade governance implementation, I configured the deployment ring via the Azure CLI inside the Southeast Asia datacenter region using an isolated sandbox perimeter scope:

1. Designing the Custom Policy Criteria (allowed-skus.json)

I engineered a strict JSON rule block that targets virtual machine resources, setting the active evaluation flag to a forceful deny effect if the requested hardware profile falls outside of approved low-cost shapes:

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Compute/virtualMachines"
      },
      {
        "field": "Microsoft.Compute/virtualMachines/sku.name",
        "notIn": [
          "Standard_B1s",
          "Standard_B2ats_v2"
        ]
      }
    ]
  },
  "then": {
    "effect": "deny"
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Provisioning and Binding the Policy Scope

I initialized the baseline target resource group perimeter and registered the schema with the control plane, passing metadata parameters as explicit flags to satisfy the Azure CLI parser rules:

# Initialize the target perimeter container
az group create --name "Marathahalli_Lab_RG" --location "southeastasia"

# Register the core custom definition rule container
az policy definition create \
  --name "restrict-vm-skus" \
  --display-name "Restrict VM SKUs to B-Series" \
  --rules allowed-skus.json \
  --mode "Indexed"

# Assign the policy enforcer live to the specific Resource Group scope
az policy assignment create \
  --name "Enforce_B_Series_Only" \
  --policy "restrict-vm-skus" \
  --display-name "Enforce B-Series Only" \
  --resource-group "Marathahalli_Lab_RG"
Enter fullscreen mode Exit fullscreen mode

โš™๏ธ Forging a Custom Least-Privilege RBAC Identity Role

Governance is incomplete without identity isolation. Instead of granting wide open contributor rights, I constructed a tailored JSON permission schema (vm-operator-role.json) defining a custom VM Restart Operator role. This role explicitly limits identity capabilities to virtual machine visibility and reboot actions, leaving write actions, configurations changes, and resource deletions sealed shut.

{
  "Name": "VM Restart Operator",
  "IsCustom": true,
  "Description": "Can only read and restart virtual machines inside the environment.",
  "Actions": [
    "Microsoft.Compute/virtualMachines/read",
    "Microsoft.Compute/virtualMachines/restart/action"
  ],
  "NotActions": [],
  "AssignableScopes": [
    "/subscriptions/YOUR_SUBSCRIPTION_ID"
  ]
}
Enter fullscreen mode Exit fullscreen mode

I programmatically extracted the subscription context and registered the custom RBAC identity blueprint live with the Azure identity control plane API:

# Dynamically fetch current active subscription ID text string
SUB_ID=$(az account show --query id --output tsv)

# Inject the active subscription path into our assignable scopes payload
sed -i "s|YOUR_SUBSCRIPTION_ID|$SUB_ID|g" vm-operator-role.json

# Register the custom RBAC identity blueprint live in the active directory tenant
az role definition create --role-definition vm-operator-role.json
Enter fullscreen mode Exit fullscreen mode

๐Ÿ““ The TAC Engineer's Troubleshooting Journal

Engineering in production means breaking things and solving real conflicts. During this implementation lab, I ran into two distinct runtime errors that provided vital architectural insights:

๐Ÿšจ 1. Top-Level Schema Mismatch Failures (Code: InvalidPolicyRule)

  • The Challenge: The initial registration utility rejected the code payload, throwing a fatal syntax validation error pointing to a schema failure on the "properties" and "mode" parameters.
  • The Root Cause: The az policy definition create engine expects the underlying --rules file configuration to start directly with the structural logic parameters (if and then). Wrapping these keys in metadata tags violates the parser's expected payload format.
  • The Fix: Stripped the outer property layers out of the allowed-skus.json file completely, and passed meta properties like --mode "Indexed" out to explicit command-line flags.

๐Ÿšจ 2. Scope Binding Failures via Missing Context Containers (Code: ResourceGroupNotFound)

  • The Challenge: The policy assignment mapping crashed, returning a terminal exception indicating that the target resource group room could not be found.
  • The Root Cause: Strict cost-control practices dictate tearing down all sandbox groups immediately after structural validations. Running an active policy assignment against an environment scope that doesn't exist crashes the engine call.
  • The Fix: Refactored the command execution queue to explicitly guarantee the presence of the resource group container (az group create) before executing assignment mappings.

๐Ÿš€ Live Workload Validation: The RequestDisallowedByPolicy Block

To prove the automated guardrails work perfectly under load, I simulated an accidental budget breach by forcing a deployment command for an unauthorized, high-tier enterprise instance shape (Standard_D4s_v3) directly against the protected resource group perimeter:

az vm create \
  --resource-group "Marathahalli_Lab_RG" \
  --name "Rogue_VM" \
  --image "Ubuntu2204" \
  --size "Standard_D4s_v3" \
  --admin-username "abhishek" \
  --generate-ssh-keys
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ธ Defensive Proof Point: The Wallet Secured

The deployment call spun for a brief moment, hit the ARM API gateway checkpoint, evaluated against the active assignment metadata constraints, and was violently rejected! The core control plane blocked resource generation immediately:

azure.core.exceptions.HttpResponseError: (InvalidTemplateDeployment) The template deployment failed because of policy violation. 
Code: InvalidTemplateDeployment
Message: The template deployment failed because of policy violation. Please see details for more information.

Exception Details: (RequestDisallowedByPolicy) Resource 'Rogue_VM' was disallowed by policy 'Enforce_B_Series_Only'.
Enter fullscreen mode Exit fullscreen mode


๐Ÿ’ก Core FinOps & AZ-104 Exam Lessons Learned

  • Deny vs. Audit Effects: The deny effect completely halts non-compliant resource allocation at the gate, protecting the budget instantly. The audit effect, conversely, allows deployments to succeed but flags them inside a compliance dashboardโ€”ideal for mapping out production estates without creating application downtime risks.
  • RBAC Scoping Precision: Security parameters inside custom role definitions require pinpoint precision. Explicitly matching actions to granular tasks ensures teams maintain access velocity without breaking zero-trust boundaries.

Top comments (0)