Automate NSG Rules with Azure Logic Apps

Schedule a Logic App to automatically inject deny rules into an NSG.

Introduction

30 Second Summary

Companies often grant temporary network access to contractors or third-party vendors. When the contract ends, someone has to remember to revoke that access manually, and forgetting means leaving a security hole wide open.

In this project, you will build an Azure Logic App that automatically blocks network traffic from a specific IP address at a scheduled date and time. No manual intervention required.

What You'll Build

A Consumption-tier Logic App that calls the Azure REST API to inject a Deny rule into a Network Security Group on a schedule, blocking inbound traffic from a specific external IP address.

By the end of this project, you'll have:

  • A test environment with a VNet, subnet, NSG, and an Ubuntu VM running nginx to demonstrate real-time connectivity changes.
  • A Consumption Logic App with a Recurrence trigger and an HTTP action that calls the Azure REST API to create NSG rules automatically.
  • A system-assigned managed identity with Network Contributor permissions, so the Logic App can authenticate to Azure without storing any secrets.
  • Secret Mission: Extend the Logic App to enforce a full bidirectional block by adding an outbound deny rule alongside the inbound one.

Are there any prerequisites?

You need an Azure subscription, Azure CLI installed on your machine, and basic familiarity with NSGs and the Azure Portal.

Set Up the Azure Test Environment

Before the Logic App can enforce anything, you need something to enforce against. The Logic App's job is to block inbound traffic to your Azure resources by injecting a Deny rule into a Network Security Group.

In this step, you will build the full test environment: a VNet, a subnet, an NSG, and an Ubuntu VM running nginx. By the end, you will be able to curl the VM's public IP and get a response, proving the network path is open.

In this step, get ready to:
  • Create a resource group, VNet, subnet, and NSG using the Azure CLI.
  • Deploy a test VM with nginx installed automatically via cloud-init.
  • Verify HTTP connectivity to the VM and note your public IP address.
Create the resource group, VNet, subnet, and NSG

Every Azure resource lives inside a resource group. You will create one to hold all the resources for this project, then build the networking layer inside it.

  • Open your terminal. Confirm you are logged in to the Azure CLI by running:
az account show
  • You should see JSON output with your subscription name and ID.

Not logged in?

If you see an error, run az login and follow the browser prompt to authenticate.

Help me troubleshoot my Azure CLI login

  • Create the resource group by running this command:
az group create \
  --name nsg-enforce-rg \
  --location eastus

What does this command do?

This creates a resource group called nsg-enforce-rg in the eastus region. All the resources you create in this project will live inside this group, making cleanup easy at the end.

  • You should see JSON output with "provisioningState": "Succeeded".
  • Create the VNet and subnet together by running:
az network vnet create \
  --resource-group nsg-enforce-rg \
  --name nsg-enforce-vnet \
  --address-prefix 10.0.0.0/16 \
  --subnet-name nsg-enforce-subnet \
  --subnet-prefix 10.0.1.0/24

What does this command do?

This creates a virtual network with the address space 10.0.0.0/16 and a subnet called nsg-enforce-subnet with the range 10.0.1.0/24. Your VM will be placed in this subnet.

  • You should see JSON output with the VNet and subnet details.
  • Create the NSG by running:
az network nsg create \
  --resource-group nsg-enforce-rg \
  --name nsg-enforce-nsg
  • Associate the NSG with the subnet by running:
az network vnet subnet update \
  --resource-group nsg-enforce-rg \
  --vnet-name nsg-enforce-vnet \
  --name nsg-enforce-subnet \
  --network-security-group nsg-enforce-nsg

Why attach the NSG to the subnet?

When an NSG is associated with a subnet, its rules apply to every resource inside that subnet. Any VM you deploy in nsg-enforce-subnet is automatically governed by nsg-enforce-nsg.

  • You should see JSON output showing nsg-enforce-nsg listed under the subnet's networkSecurityGroup field.
  • Add an inbound allow rule for HTTP traffic by running:
az network nsg rule create \
  --resource-group nsg-enforce-rg \
  --nsg-name nsg-enforce-nsg \
  --name AllowHTTP \
  --priority 100 \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefixes '*' \
  --destination-port-ranges 80 \
  --access Allow

What does this rule do?

This creates a rule called AllowHTTP that permits inbound TCP traffic on port 80 from any source. Priority 100 is the highest priority a custom rule can have (lower number = higher priority).

NSG rules are evaluated in priority order. The first matching rule wins and all later rules are skipped. The Logic App will use this behavior later to block specific traffic.

  • You should see JSON output confirming the rule with "access": "Allow" and "destinationPortRange": "80".

Seeing a permission error?

Make sure your Azure account has Contributor or Owner access on the subscription. Run az account show to confirm you are logged in to the correct subscription.

Help me troubleshoot my Azure permissions

Create a test VM with nginx

You need an HTTP endpoint to test connectivity against. A lightweight Ubuntu VM with nginx installed gives you exactly that.

  • Create a cloud-init configuration file that tells Azure to install nginx when the VM boots. Run this command to create the file:
cat <<EOF > cloud-init.txt
#cloud-config
package_upgrade: true
packages:
  - nginx
runcmd:
  - systemctl start nginx
  - systemctl enable nginx
EOF

What is cloud-init?

Cloud-init is a standard tool for automating the initial setup of cloud VMs. Instead of SSHing into the VM to install software manually, you hand Azure a config file and the VM configures itself on first boot.

  • Confirm the file was created by running:
cat cloud-init.txt
  • You should see the #cloud-config content printed to your terminal.
  • Create the VM by running this command:
az vm create \
  --resource-group nsg-enforce-rg \
  --name nsg-enforce-vm \
  --image Ubuntu2204 \
  --size Standard_B1s \
  --vnet-name nsg-enforce-vnet \
  --subnet nsg-enforce-subnet \
  --nsg "" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --custom-data cloud-init.txt

What does this command do?

  • --image Ubuntu2204 picks the Ubuntu 22.04 LTS image.
  • --size Standard_B1s selects the smallest (cheapest) VM size at about $0.01/hour.
  • --nsg "" prevents Azure from creating a second NSG on the VM's network interface. Your subnet-level NSG already controls traffic.
  • --custom-data cloud-init.txt hands the cloud-init file to the VM so nginx installs automatically on first boot.

This takes 1-3 minutes

Azure is provisioning the VM, setting up its disk, creating a public IP, and running the cloud-init script. Wait for the command to complete and return JSON output.

  • When the command finishes, you should see JSON output that includes a publicIpAddress field. Note this value. This is your VM's public IP address.

VM creation failed?

If you see a quota or capacity error, try a different region by deleting the resource group and starting over with a different --location value (e.g. westus2 or northeurope).

If you see cloud-init.txt not found, make sure you ran the cat <<EOF command first and that your terminal's current directory contains the file.

Help me troubleshoot my VM creation error

Verify initial connectivity

The VM is deployed and nginx should be running. Now you need to confirm you can reach it over HTTP and note your own public IP address for later.

  • Retrieve the VM's public IP by running:
az vm show \
  --resource-group nsg-enforce-rg \
  --name nsg-enforce-vm \
  --show-details \
  --query publicIps \
  --output tsv
  • You should see a single IP address printed to your terminal. Copy this value.
  • Test HTTP connectivity to the VM by running this command, replacing the IP with your VM's public IP:
curl http://[[VM_PUBLIC_IP="your VM's public IP address"]]
  • You should see a block of HTML in your terminal. This is the default nginx welcome page, confirming the web server is running and your NSG is allowing HTTP traffic through.

Give nginx a minute

If curl returns Connection refused or times out, the cloud-init script may still be running. Wait 30-60 seconds and try again.

  • Find your own public IP address by running:
curl ifconfig.me
  • You should see a single IP address printed to your terminal. This is the external IP that the Logic App will block in a later step. Copy and save this value somewhere handy.

Why do I need my own IP?

The Logic App will create an NSG Deny rule that blocks inbound traffic from a specific source IP. That source IP is your public IP address. By noting it now, you have the exact value to plug into the Logic App's HTTP action later.

Curl timing out?

If curl hangs or times out, check these common causes:

  • Confirm the AllowHTTP rule exists by running az network nsg rule list --resource-group nsg-enforce-rg --nsg-name nsg-enforce-nsg --output table.
  • Make sure you used --nsg "" when creating the VM. If a NIC-level NSG was created, it may be blocking port 80.
  • Wait 60 seconds and retry. The cloud-init script needs time to install and start nginx.

Help me troubleshoot my curl timeout

Your test environment is live and reachable. Next up, you will create the Logic App and give it permission to modify this NSG.

Create the Logic App and Configure Identity

Your test environment is ready. You proved the VM responds to HTTP requests on port 80, so the NSG is doing its job.

Now you need something that can modify that NSG automatically on a schedule. Azure Logic Apps is a workflow automation service that can call Azure APIs directly.

In this step, you'll create a Logic App and set up a managed identity so it has permissions to write security rules.

In this step, get ready to:
  • Create a Consumption Logic App in the Azure Portal.
  • Enable a system-assigned managed identity on the Logic App.
  • Grant the identity Network Contributor permissions on the NSG.
Create a Consumption Logic App in the Azure Portal

The Logic App is the automation engine for this project. It runs your workflow on a schedule without any servers to manage.

  • In the Azure Portal, type Logic apps in the top search bar.
  • Select Logic apps from the results.
  • Click Add.
  • For Subscription, select your Azure subscription.
  • For Resource Group, select nsg-enforce-rg.
  • For Logic App name, enter nsg-enforce-logic-app.
  • For Region, select the same region you used for your resource group.
  • For Plan type, select Consumption.
  • Click Review + create.
  • Click Create.
  • After the deployment completes, click Go to resource.

Why Consumption instead of Standard?

Consumption Logic Apps are pay-per-execution. Your first 4,000 built-in action executions are free per Azure subscription.

Standard Logic Apps require a fixed hosting plan starting at around $185 per month. For a workflow that runs once, Consumption is essentially free.

The Logic App's Overview page loads. The Status shows Enabled.

Don't see the Logic App overview?

Click Notifications (the bell icon in the top right) to check for deployment errors. Make sure you selected Consumption as the plan type and a supported region.

My Logic App deployment failed in the Azure Portal. What should I check?

Enable the system-assigned managed identity

The Logic App needs a way to authenticate to Azure when it modifies NSG rules. A managed identity handles this without storing any passwords or API keys.

  • In the Logic App's left menu, click Identity under the Settings section.
  • On the System assigned tab, toggle Status to On.
  • Click Save.
  • A confirmation dialog appears asking you to enable the managed identity. Click Yes.
  • Copy the Object (principal) ID that now appears on the page. Save it somewhere accessible for the next substep.

What is a managed identity?

A managed identity gives your Azure resource its own identity for authenticating to other Azure services. Azure handles creating and rotating the credentials automatically.

You never see or manage a password. Microsoft recommends managed identities as the authentication method for Logic Apps.

Don't see the Object ID?

Make sure you clicked Save after toggling the status to On. The Object ID only appears after saving and confirming the dialog.

I enabled the managed identity but the Object ID is not showing. What should I check?

Assign Network Contributor role on the NSG

The managed identity alone does not have any permissions yet. You need to grant it a specific role that allows it to create and modify security rules.

  • Switch back to your terminal.
  • Grant the permissions by running this command:
az role assignment create \
  --assignee [[LOGIC_APP_OBJECT_ID="your Logic App Object ID"]] \
  --role "Network Contributor" \
  --scope $(az network nsg show --resource-group nsg-enforce-rg --name nsg-enforce-nsg --query id --output tsv)

What does this command do?

  • --assignee specifies who gets the permission. This is the Object ID you copied from the managed identity page.
  • --role "Network Contributor" is a built-in Azure role that includes permission to create and modify NSG security rules.
  • --scope limits the permission to just your NSG. The nested az network nsg show command retrieves the NSG's full resource ID automatically.
  • Look for roleDefinitionName showing Network Contributor in the JSON output to confirm the role was assigned.

Seeing an error?

  • Verify you pasted the correct Object ID from the managed identity page.
  • If your Azure CLI session expired, run az login to reauthenticate.
  • Make sure the NSG nsg-enforce-nsg exists in the resource group nsg-enforce-rg.
  • If you are using Windows Command Prompt, switch to PowerShell. The $() syntax does not work in Command Prompt.

I'm getting an error when assigning the Network Contributor role. How do I fix this?

Your Logic App is created and authorized to modify NSG rules. Next, you'll build the workflow that fires on a schedule and creates a deny rule to block traffic.

Build the Workflow

Your Logic App has an identity and the permissions it needs to modify the NSG. Now it needs instructions for what to do and when to do it.

In this step, you will build the actual workflow inside the Logic App Designer. You will add a Recurrence trigger that fires at a specific date and time, followed by an HTTP action that calls the Azure REST API to inject a Deny rule into your NSG.

In this step, get ready to:
  • Add a Recurrence trigger that fires at a scheduled date and time.
  • Add an HTTP action that calls the Azure REST API to create a Deny NSG rule.
  • Save and review the workflow to confirm it is enabled and waiting.
Add the Recurrence trigger

Every Logic Apps workflow starts with a trigger that defines when the workflow runs. The Recurrence trigger is a built-in schedule trigger that fires at a time you specify.

  • In the Azure Portal, navigate to your nsg-enforce-logic-app Logic App resource.
  • On the left sidebar under Development Tools, click Logic app designer.
  • Click Add a trigger to open the trigger selection pane.
  • In the search box, type Schedule and select the Recurrence trigger from the results.

The Recurrence trigger configuration pane opens with fields for setting the schedule.

  • Set Interval to 1.
  • Set Frequency to Day.
  • Select Time Zone and choose your local time zone from the dropdown.
  • In the Start Time field, enter a date and time approximately 5 minutes from now in ISO 8601 format.

The start time format is YYYY-MM-DDThh:mm:ss. For example, if your current local time is 2:25 PM on January 15, 2024, enter:

2024-01-15T14:30:00

Do not add a trailing Z to your start time

When you select a time zone, you must not add a Z to the end of your start time value. The Z signifies UTC format, and Logic Apps will ignore your selected time zone entirely if it sees it.

Why set the start time to 5 minutes from now?

If you save a Recurrence trigger without a start time, it fires immediately. Setting the start time 5 minutes in the future gives you enough time to finish building the workflow and save it before the trigger fires.

The trigger recurs every day at this time, but you only need it to fire once. After it runs, you will disable the Logic App in the next step.

Don't see Time Zone or Start Time fields?

These fields may be hidden under the Advanced parameters dropdown in the Recurrence trigger pane. Click Advanced parameters and check the boxes for Time Zone and Start Time to make them visible.

Still stuck? Help me configure the Recurrence trigger in my Logic App.

Add the HTTP action to create the NSG deny rule

The trigger defines when the workflow runs. Now you need an action that defines what happens. The built-in HTTP action lets you call any REST API directly from your workflow.

  • Below the Recurrence trigger in the designer, click the + (plus sign), then select Add an action.
  • In the search box, type HTTP and select the built-in HTTP action (not the HTTP + Webhook option).

The HTTP action configuration pane opens. Configure each field as follows.

  • Set Method to PUT.
  • In the URI field, paste the following URL (replacing the subscription ID with your own):
https://management.azure.com/subscriptions/[[SUBSCRIPTION_ID="your Azure subscription ID"]]/resourceGroups/nsg-enforce-rg/providers/Microsoft.Network/networkSecurityGroups/nsg-enforce-nsg/securityRules/DenyInboundFromExternal?api-version=2023-05-01

What is this URL?

This is the Azure REST API endpoint for creating or updating an NSG security rule. The URL includes your subscription, resource group, NSG name, and the new rule name DenyInboundFromExternal.

The PUT method tells Azure to create the rule if it does not exist, or update it if it already does.

Find your subscription ID

In the Azure Portal, search for Subscriptions in the top search bar. Click your subscription to see its Subscription ID on the overview page.

Next, you need to set the request headers and body for the HTTP action.

  • In the Headers section, add a header with key Content-Type and value application/json.
  • In the Body field, paste the following JSON (replacing the source IP with the public IP you noted in Step 1):
{
  "properties": {
    "protocol": "*",
    "sourceAddressPrefix": "[[MY_PUBLIC_IP_ADDR="your public IP address from Step 1"]]",
    "destinationAddressPrefix": "*",
    "access": "Deny",
    "destinationPortRange": "*",
    "sourcePortRange": "*",
    "priority": 200,
    "direction": "Inbound"
  }
}

What does this JSON body do?

This body tells Azure to create a Deny rule on the NSG. It blocks all inbound traffic (any protocol, any port) from your specific public IP address.

  • "access": "Deny" blocks the traffic instead of allowing it.
  • "sourceAddressPrefix" targets only your specific public IP. All other IPs are unaffected.
  • "priority": 200 sets where this rule sits in the NSG evaluation order. Lower numbers are evaluated first.
  • "direction": "Inbound" means the rule applies to traffic coming into the NSG from outside.

Finally, configure the HTTP action to authenticate using the Logic App's managed identity.

  • In the HTTP action pane, open the Advanced parameters dropdown and check Authentication.
  • From the Authentication type list, select Managed identity.
  • From the Managed identity list, select System-assigned managed identity.
  • In the Audience field, enter https://management.azure.com/.

Why use a managed identity instead of an API key?

A managed identity lets Azure handle authentication automatically. There are no passwords or secrets to store, rotate, or leak. The Logic App proves its identity to Azure Resource Manager the same way a person proves theirs with a badge.

The Audience field tells Azure which resource the token is for. https://management.azure.com/ is the audience for Azure Resource Manager, which handles NSG operations.

Don't see the Authentication fields?

Make sure you clicked Advanced parameters and checked the Authentication checkbox. The authentication fields only appear after you enable them from this dropdown.

If you see the Authentication type dropdown but not Managed identity as an option, confirm that you enabled the system-assigned managed identity on the Logic App in Step 2.

Help me set up managed identity authentication on my HTTP action.

Save and review the workflow
  • On the designer toolbar, click Save.
  • Navigate to the Logic App's Overview page by clicking Overview in the left sidebar.

On the Overview page, confirm that the Logic App's Status shows Enabled. You should also see the Recurrence trigger listed with the scheduled start time you entered.

Logic App shows Disabled?

If the status shows Disabled, click Enable in the toolbar on the Overview page. The Logic App must be enabled for the trigger to fire at the scheduled time.

If the scheduled time has already passed and the Logic App shows a run in its history, the trigger fired before you finished setting up. Go back to the designer, update the start time to a new time 5 minutes from now, and save again.

Help me troubleshoot my Logic App trigger not firing at the right time.

Your workflow is armed and waiting. In the next step, you will watch the Logic App fire, inspect the NSG rule it creates, and confirm that inbound traffic from your IP is blocked.

Verify the Block

In the previous step, you built a workflow that calls the Azure REST API to inject a deny rule into your NSG at a scheduled time. Your Logic App is now armed and counting down.

In this step, you'll confirm the automation worked end-to-end. You'll check the run history, inspect the new NSG rule, and prove that your IP is actually blocked from reaching the VM.

In this step, get ready to:
  • Monitor the Logic App run history for a successful execution.
  • Inspect the deny rule the Logic App created on the NSG.
  • Test connectivity to confirm inbound traffic from your IP is blocked.
Monitor the Logic App run

The Logic App fires at the start time you configured in the Recurrence trigger. If that time hasn't passed yet, wait a few minutes before continuing.

  • In the Azure Portal, search for nsg-enforce-logic-app and select it from the results.
  • In the left menu, click Overview.
  • Scroll down to the Runs history section.
  • Click on the most recent run entry to open it.

You should see a green checkmark and a Succeeded status for the overall run.

  • Click on the HTTP action step to expand its details.
  • Check the Status code field. It should show 200 or 201.

What do these status codes mean?

A 201 status means the deny rule was created for the first time. A 200 status means the rule already existed and was updated.

Either status confirms the Logic App successfully called the Azure REST API and wrote the rule to your NSG.

Run shows Failed?

  • Click on the failed HTTP action to see the error message. A 403 error means the managed identity doesn't have the right permissions on the NSG. Go back to the NSG's Access control (IAM) blade and verify the Network Contributor role assignment.
  • A 404 error usually means a typo in the REST API URL. Double check the subscription ID, resource group name (nsg-enforce-rg), and NSG name (nsg-enforce-nsg) in the HTTP action's URI field.
  • If no run appears at all, the scheduled time may not have passed yet. Wait a few more minutes and refresh the page.

Why is my Logic App run failing?

Inspect the NSG rule in the portal

A successful run means the API call went through. Now you need to verify the actual deny rule landed on the NSG with the correct settings.

  • In the Azure Portal search bar, type nsg-enforce-nsg and select it from the results.
  • In the left menu under Settings, click Inbound security rules.

You should see two custom rules in the list: AllowHTTP at priority 100 and DenyInboundFromExternal at priority 200.

  • Click on DenyInboundFromExternal to view its details.
  • Confirm the Source field shows your public IP address.
  • Confirm the Action field is set to Deny and the Direction is Inbound.

What does this deny rule do?

The DenyInboundFromExternal rule blocks all inbound traffic from your specific public IP address to any resource behind this NSG. The protocol is set to *, meaning it blocks every protocol, not just HTTP.

Your Logic App created this rule automatically at the scheduled time. No manual intervention was needed.

Don't see the deny rule?

  • Go back to the Logic App's Runs history and confirm the run actually succeeded. A failed run means the rule was never created.
  • Make sure you're looking at Inbound security rules, not Outbound security rules. The deny rule is configured as an inbound rule.

Why isn't the deny rule showing up in my NSG?

Test connectivity and confirm the block

The rule is on paper. Now you need proof that it actually stops traffic. In Step 1, you used curl to confirm nginx was reachable on the VM. Time to run the same test.

  • Open your terminal and run the same curl command from Step 1:
curl http://[[VM_PUBLIC_IP="your VM's public IP address"]]

The request should hang and eventually time out, or return a Connection refused error. This is the proof that the Logic App did its job.

Why does a timeout prove the block?

In Step 1, this same curl command returned the default nginx welcome page instantly. Now the NSG deny rule is dropping packets from your IP before they reach the VM.

The difference between a fast response and a timeout is the signal. Nothing changed on the VM itself. The Logic App changed the network rules in front of it.

Still getting a response?

  • Go back to the NSG and verify the DenyInboundFromExternal rule exists in the inbound rules. If it's missing, the Logic App run may have failed.
  • Check that the source IP in the deny rule matches your actual current public IP. Your IP can change if you switch networks or restart your router.
  • Wait 30 seconds and try the curl command again. NSG rule changes can take a moment to propagate.

Why can I still reach my VM after the deny rule was created?

Secret mission

Create a Full Bidirectional Block

Your Logic App blocks inbound traffic from a specific IP, but what about the other direction? Traffic can still flow outbound from your Azure resources to that same IP. Extend your workflow to deny outbound traffic too, creating a complete bidirectional block.

Before you go

Clean Up Your Resources

This project created Azure resources that cost money if left running. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Cost warning

The test VM is the main cost driver at approximately $0.01/hour for a B1s instance. The VNet, NSG, and public IP also have minor associated costs.

The Consumption Logic App has no idle cost. It only charges per execution. If you are done with this project, deleting the resource group is the safest way to stop all charges.

Resources you used:

  • An Azure resource group containing all project resources.
  • A VNet with a subnet and an associated NSG.
  • A B1s Ubuntu VM with a public IP address running nginx.
  • A Consumption Logic App with a system-assigned managed identity.
  • A Network Contributor RBAC role assignment scoped to the NSG.

Keep everything running

No action needed. Choose this if you are still actively experimenting with the Logic App or want to add more rules.

  • Be aware that the VM costs approximately $0.01/hour while it is running.
  • The Consumption Logic App has no idle cost, so it is safe to leave enabled.
  • Consider pausing or deleting resources when you are done experimenting to avoid ongoing charges.

Pause - I'll come back to this later

Shut down the VM to stop compute billing while keeping your entire environment intact.

  • Deallocate the VM to stop compute charges by running this command:
az vm deallocate --resource-group [[RG_NAME="your resource group name"]] --name [[VM_NAME="your VM name"]]

What does deallocating do?

Deallocating stops the VM and releases its compute resources, so you stop paying for the VM itself. The disk, VNet, NSG, and public IP remain in place so you can start the VM again later.

  • To disable the Logic App so it does not fire again, navigate to the Logic App in the Azure Portal and click Disable on the Overview page.
  • When you are ready to resume, start the VM again by running:
az vm start --resource-group [[RG_NAME="your resource group name"]] --name [[VM_NAME="your VM name"]]

Delete - I don't want to use this again

Remove all project resources and stop all charges. This is the recommended option if you have finished the project.

  • Delete the entire resource group by running this command:
az group delete --name [[RG_NAME="your resource group name"]] --yes --no-wait

What does this command do?

This deletes the resource group and everything inside it, including the VM, VNet, NSG, public IP, Logic App, and managed identity. The --no-wait flag lets the deletion happen in the background so you do not have to wait for it to finish.

  • Verify deletion is in progress by navigating to Resource groups in the Azure Portal. Your resource group should show as deleting or no longer appear in the list.

Mission accomplished

That's a Wrap!

Nice work! You just built an automated network enforcement system using Azure Logic Apps. You now have a working pattern for enforcing security policies on a schedule, with zero manual intervention.

Here's what you learned:

  • Built a Consumption Logic App with a Recurrence trigger and an HTTP action that calls the Azure REST API to create NSG deny rules on a schedule.
  • Configured a system-assigned managed identity with Network Contributor permissions to authenticate securely without storing any credentials.
  • Verified end-to-end that inbound connectivity from a specific external IP was blocked after the Logic App fired at the scheduled time.
  • Secret Mission: Extended the Logic App to enforce a full bidirectional block with both inbound and outbound deny rules.

Ready to quiz yourself?