Stopping and starting Azure Application Gateway on-demand and on a schedule

Stopping and starting Azure Application Gateway on-demand and on a schedule

Azure Application Gateway is a load balancer that allows you to manage traffic to your web applications. It offers a Web Application Firewall (WAF) feature, which is advertised to protect web applications against the OWASP Top Ten attacks.

Some have described Azure WAF as a sort of a “silver bullet” against web application attacks. Lately, I’ve been doing penetration testing against Azure WAF to see how well its OWASP rules truly fare in practice. For that purpose, I set up a vulnerable web application in Azure and put it behind an Azure Application Gateway and its WAF with OWASP rules.

Running the Azure Application Gateway with WAF costs about 9,50€ euros per day, making it a bit under 300€ euros per month (slightly less in US dollars). Normally, you want to have it running at all times — after all, you never know at what time of day hackers are on the move. However, because I was not testing my vulnerable dummy web app 24/7, I only needed to have the application gateway running while performing the tests.

To save some money, I looked for a way to stop the application gateway after completing my testing session. Unfortunately, there’s no button in Azure Portal that allows us to stop and start the application gateway on-demand. Microsoft has also said that they are not planning on introducing this functionality. Luckily, we can stop and start the application gateway with PowerShell!

Stopping and starting the application gateway on-demand

To manage the Azure application gateway on-demand with PowerShell, you first need to install the Az PowerShell module on your computer. This happens by starting Windows PowerShell as an administrator and running the below command.

Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force

After you’ve installed the Az module, you are ready to run the script below. It will first connect to your Azure subscription, prompting you for credentials. It will then get the application gateway object and check its status. If the application gateway is running and you’ve specified that you want it stopped, the script will stop the gateway. And vice versa, if the application gateway is stopped and you’ve specified that you want it up and running again, the script will start the gateway.

To execute the script, you need to provide the Azure subscription ID, the resource group name, the app application gateway name, and either $true (to start) or $false (to stop) to change the application gateway state. So, for example, to stop the application gateway, you’d run the following command in Windows PowerShell.

. "<local script file directory path>.ps1" -subscriptionId "<your subscription ID>" -resourceGroupName "<your resource group name>" -appGatewayName "<your application gateway name>" -enabled $false

Stopping the application gateway on a schedule with Azure Functions

If you are anything like me, the problem with the above on-demand approach is that you sometimes forget to manually shut down the application gateway after you are done with it. For this same reason, I love the feature virtual machines have that makes them automatically shut down at a certain time of day. I wanted the same functionality for my application gateway, so it would always stop in the evening if it were still running. For this purpose, I quickly whipped up an Azure function for the job. Here are step-by-step instructions that allow you to do the same.

Create the Function App resource

To create the Azure Function App resource, do the following:

  1. Create a new resource group:
    • Select a billing subscription
    • Give the resource group a descriptive name (following agreed upon naming conventions if such exist).
    • Select a region near you.
  2. Go to the resource group after it has been deployed.
  3. Click on Create resources.
  4. Choose to create a Function App.
  5. On the Basics tab:
    • The subscription and resource group should already be selected. Leave them as they are.
    • Give your function app a descriptive name.
    • Publish: Code
    • Runtime stack: PowerShell Core
    • Version: 7.0 (at the time of this writing)
    • Finally, select the same region as what you chose for the resource group.
  6. On the Hosting tab:
    • Create a new storage account with a descriptive name.
    • Operating System: Windows
    • Plan type: Consumption (Serverless)
  7. On the Monitoring tab:
    • Choose to enable Application Insights.
    • Give the resource a descriptive name, and select the same region as what you chose for the resource group and the function app.
    • Plan type: Consumption (Serverless)
  8. On the Tabs tab you can optionally add descriptive tags for the resource to provide more information about it. Your subscription administrator might have even set up some Azure Policies that require you to tag the resources you create.
  9. Finally, on the Review + create tab, hit on the Create button.

Configure the Function app settings

After the deployment completes, click on Go to resource.

  1. Go to the App files blade.
  2. While host.json is selected from the dropdown, add "functionTimeout": "00:10:00" to the root of the JSON object, and click Save. This increases the maximum allowed runtime of the function to 10 minutes instead of the default 5 minutes. This is required, because stopping and starting the application gateway typically takes around 6 minutes. After the change, the host.json file should look something like below.

  3. Remaining on the App files blade, select requirements.psd1 from the dropdown, and uncomment the 'Az' = '6.*' line (remove the #). This will take the required Az PowerShell module into use in our function. The version number might have increased by the time of this writing. Remember to Save before proceeding to the next step. The file contents should now look similar to the example below.

    Note that for the file changes to come into effect, an application restart is required. This will happen automatically in the next step when we save the application settings. However, if you are doing the steps in a different order for some reason, make sure to restart the app manually via the Overview blade.
  4. Go to the Configuration blade, and add three new application settings.
    Name Value
    subscriptionId The ID of the subscription where your application gateway is located.
    resourceGroupName The name of the resource group where your application gateway is located.
    appGatewayName The name of the application gateway resource you want to shut down on a schedule.
  5. Remember to click on Save at the top to take the new application settings into effect.
  6. Then, go to the Identity blade.
  7. Change the System assigned management identity status to On, and click on save. We need to enable this feature to give our Azure function permissions to manage the application gateway.
  8. Go to the application gateway resource and there to the Access control (IAM) blade.
  9. Choose to Add role assignment.
    • Role: Network Contributor
    • Assign access to: Function app (under System assigned managed identity).
    • Select the function app from the list, and click on Save.

Create the function for stopping the application gateway

Finally, let’s create the function that will actually stop our application gateway on a schedule.

  1. Go to back to the Functions App resource, and there onto the Functions blade.
  2. Click Add to create a new function.
    • Select Timer trigger as the template.
    • Give the function a name (e.g., StopAppGateway)
    • Schedule it to run at a time when you want to stop the application gateway. I personally wanted the application gateway to shut down at 6 o’clock in the evening (UTC), so I used the following CRON expression: 0 0 18 * * *.
      Note that by default you always need to specify the CRON expression according to the UTC time zone. If you prefer to schedule your function to run using some other time zone, you can specify it using the WEBSITE_TIME_ZONE setting.
  3. When the function has been created, go to the Code + Test blade, copy-paste the code below to the function.

    The function code will first authenticate to the subscription and get a reference to the application gateway resource with the system assigned managed identity of the Azure function app. Then, it will check if the application gateway is running and if yes, it will stop it. If the application gateway is in some other state (Stopped, Stopping or Starting), the function will instead write a message to the logs indicating that the application gateway was already stopped and no action has been performed on it.

  4. Finally, click on Save

The application restart we caused earlier when saving configurations triggered the installation of the Az PowerShell module. It takes a little while for that process to complete. If you were to execute the function manually immediately after creation, it would most likely fail because of the missing module.

You can check when modules have been successfully installed via Kudu. You can open Kudu by going to the Advanced Tools blade of your function app and clicking on the Go link. Under the Debug console dropdown, select either one of the shells. Browse to data and then Managed dependencies to see if all the modules have been installed. Personally, I’ve experienced that it sometimes takes multiple tries for the module installation to succeed. I’d give it about half an hour, and then check back to ensure that at least 10 minutes have passed since the most recently created folder time stamp before attempting to execute the function.

Getting the application gateway up and running again

You can always create a similar function that starts up the application gateway in the morning if you like (replace “Stop-AzApplicationGateway” with “Start-AzApplicationGateway” and adjust the CRON expression to match your desired schedule). However, a manual startup was a better option for my purposes because I didn’t do testing against the WAF every day. Still, I wanted to make starting the application gateway as effortless as possible, so I quickly created another handy Azure function for the purpose, this time utilizing the HTTP trigger.

You can also just run the script presented at the top of this article locally on your computer if you feel like this setup is way too fancy for you. I just thought it would be fun to start my application gateway this way, and it only takes a moment to set up, so why not?
  1. In the same Function App resource, let’s first go on to the Authentication blade. We’ll want to protect the HTTP triggered function with Azure AD, so no one outside of our tenant will be able to trigger it, and hence start the application gateway.
  2. Click on Add identity provider, and select the following settings.
    • Identity provider: Microsoft
    • Otherwise you can use the default settings. Just click on Add when ready.
  3. Go back to the Functions blade and click Add to create a second function.
    • Select HTTP trigger as the template.
    • Give the function a name (e.g., StartAppGateway)
    • Select Anonymous in the Authorization level dropdown to avoid having the function key in the URL. We’ve already protected the function with Azure AD.
  4. When the function has been created, go to the Code + Test blade and add the code below to the function.

    Again, the function code will first authenticate to the subscription and get a reference to the application gateway resource with the system assigned managed identity of the Azure function app. Then, it will check if the application gateway is stopped and if yes, it will start it. If the application gateway is in some other state (Started, Starting or Stopping), the function will instead send a response back to the browser, telling the current state of the application gateway, and indicating that no action was performed.

  5. Click on Save.
  6. You can now test the function by clicking on the Get Function Url button, and copy-pasting the URL into the browser address bar. On the first time, you’ll be asked to consent for some permissions.

That’s it! We can now save the function URL to our browser bookmarks bar and simply click on that button to start the application gateway on-demand.

Note that the request time out for app services is 230 seconds. This means that you’ll get a timeout error in the browser when the application gateway is being started. This happens because it typically takes somewhere around 6 minutes to start up the application gateway. The function app will wait for it to happen, and won’t respond back to the browser within those allowed 230 seconds. Still, the application gateway will get started successfully in the background. The implementation could be improved to avoid this by making the function asynchronous, but for my penetration testing purposes taking such measures was not worth the time and effort.

Afterword

Normally, when you have a web application running in production, you want to have an Azure application gateway with a web application firewall up and running at all times. However, for some situations, like my experiments, you only need to have the application gateway enabled for a small amount of time. It is a lot quicker to stop and start it with PowerShell than delete and recreate it via Azure Portal every time you switch tasks.

Did you find this article useful? In what kind of situations are you looking to stop and start the application gateway on-demand or on a schedule? Let me know in the comments section below!

If you enjoyed this article and would like to read more of the content I produce, feel free to look around. And if you’d like to get notified of future posts, make sure to follow me on social media, particularly on Twitter, for that purpose. You are also welcome to subscribe to my newsletter, where I occasionally tell a little bit about what has been going on lately and give a recap of my most recently published articles.

Thank you for reading; it is always appreciated, and until next time!

Laura



4 thoughts on “Stopping and starting Azure Application Gateway on-demand and on a schedule”

  • I have a quick question. Is it possible to update the application gateway when it is in stopped state? e.g. I wanted to update the backend pool and it takes me 15-30 mins to save the application gateway once I update the backend pool. So question is can I do this?
    1. Stop the Application Gateway
    2. Do the updations
    3. Start the Application Gateway

    Do you think this way it will be faster?

    Thanks
    Rushi

  • Hi Laura,
    Thanks for this helpful article. I just wanted to let you know that in order to get this to work, your article was fine, but I had to make two tweaks

    App files > requirements.psd1
    – – I had to explicitly call the Az.Modules I required.
    ‘Az.Accounts’ = ‘2.9.1’
    ‘Az.Network’ = ‘4.7.0’

    App files > profile.ps1
    – I had to explicitly import the Az.Modules I required.
    Import-Module Az.Accounts -RequiredVersion ‘2.9.1’
    Import-Module Az.Network -RequiredVersion ‘4.7.0’

    Not sure exactly why, but just calling ‘Az’ = ‘6.*’, or similar, no longer seems to work.

    All the best and thanks for your help!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.