Loading...

Enable IP restriction for a public facing App service

Enable IP restriction for a public facing App service


In this blog article, we will cover how to control the app service deployment to support only public facing app service with IP restriction enabled.

 
Note: The policy should allow the end-user experience to be the same whether they deploy the app service using the Azure portal, ARM template, or terraform.

Policy Definition

Note: The policy below is applicable only for the resource type Microsoft.Web/sites.


{

    "mode": "All",

    "policyRule": {

      "if": {

        "allOf": [

          {

            "field": "Microsoft.Web/sites/publicNetworkAccess",

            "equals": "Enabled"

          },

          {

            "anyOf": [

              {

                "allOf": [

                  {

                    "field": "Microsoft.Web/sites/siteConfig.ipSecurityRestrictionsDefaultAction",

                    "notEquals": "Deny"

                  }

                ]

              },

              {

                "allOf": [

                  {

                    "field": "Microsoft.Web/sites/siteConfig.ipSecurityRestrictionsDefaultAction",

                    "equals": "Deny"

                  },

                  {

                    "not": {

                      "count": {

                        "field": "Microsoft.Web/sites/siteConfig.ipSecurityRestrictions[*]",

                        "where": {

                          "count": {

                            "value": "[if(equals(parameters('environment'), 'prod'), parameters('allowedIPAddressesProd'), parameters('allowedIPAddressesDev'))]",

                            "name": "allowedIpAddress",

                            "where": {

                              "allOf": [

                                {

                                  "value": "[if(equals(current('Microsoft.Web/sites/siteConfig.ipSecurityRestrictions[*].ipAddress'), 'Any'), 'true', ipRangeContains(current('allowedIpAddress'), current('Microsoft.Web/sites/siteConfig.ipSecurityRestrictions[*].ipAddress')))]",

                                  "equals": true

                                }

                              ]

                            }

                          },

                          "greater": 0

                        }

                      },

                      "equals": "[length(field('Microsoft.Web/sites/siteConfig.ipSecurityRestrictions[*]'))]"

                    }

                  }

                ]

              }

            ]

          }

        ]

      },

      "then": {

        "effect": "[parameters('effect')]"

      }

    },

    "parameters": {

      "effect": {

        "type": "String",

        "metadata": {

          "displayName": "Effect",

          "description": "Enable or disable the execution of the policy."

        },

        "allowedValues": [

          "Audit",

          "Deny",

          "Disabled"

        ],

        "defaultValue": "Audit"

      },

      "environment": {

        "type": "String",

        "metadata": {

          "displayName": "Environment",

          "description": "Select the environment to apply the correct IP restrictions."

        },

        "allowedValues": [

          "dev",

          "prod"

        ],

        "defaultValue": "prod"

      },

      "allowedIPAddressesDev": {

        "type": "Array",

        "metadata": {

          "displayName": "Allowed IP addresses for Dev",

          "description": "Array with allowed public IP addresses for the Dev environment."

        },

        "defaultValue": [

          "203.0.113.0/24"

        ]

      },

      "allowedIPAddressesProd": {

        "type": "Array",

        "metadata": {

          "displayName": "Allowed IP addresses for Prod",

          "description": "Array with allowed public IP addresses for the Prod environment."

        },

        "defaultValue": [

          "198.51.100.0/24",

          "203.0.113.5/32"

        ]

      }

    }

  }

 

 

 

 

Explanation about policy

The above policy will not allow any public-facing app service to be created unless their public access is "Disabled" or it satisfies the following conditions:

  1. Enabled from selected network
  2. Default action should be deny
  3. Only trusted IP’s are allowed based on the environment i.e above policy is using 198.51.100.0/25 and 203.0.113.5/32 as an example.

    Note: You can add more trusted IPs, the above IPs are just examples.

 

KrishnaM2265_0-1729591784255.png

 

 

 

 

 

 

 



 

Deployment using Azure portal

If we try to deploy app service using azure portal, in the networking tab we could see only two option i.e enable public access or disable public access.

KrishnaM2265_1-1729591784265.png

 

If we keep enable public access as "ON", we will be blocked from creating the app service with the following error.

KrishnaM2265_2-1729591784341.png

 

 

Now we know that the portal only supports either enabling or disabling public access for the app service, so we need to create another policy that changes the setting from disable public access to enable public access with IP restrictions in place. Please find the policy below, which will perform the deployment after the app service is deployed through the Azure portal.

Policy definition

The policy below identifies resources like Microsoft.Web/sites and if it finds the app service has public access disabled, it will modify the networking setting of the app service. Via the Azure portal, it is not possible to create an app service with a firewall, and it requires manual changes to be done.


Note: The policy below will automatically enable IP restrictions on newly created app services using the Azure portal with public access disabled for an app service.

 

{

    "mode": "All",

    "policyRule": {

      "if": {

        "allOf": [

          {

            "field": "type",

            "equals": "Microsoft.Web/sites"

          },

          {

            "anyOf": [

              {

                "field": "Microsoft.Web/sites/publicNetworkAccess",

                "exists": "false"

              },

              {

                "field": "Microsoft.Web/sites/publicNetworkAccess",

                "equals": "Disabled"

              }

            ]

          }

        ]

      },

      "then": {

        "effect": "[parameters('effect')]",

        "details": {

          "type": "Microsoft.Web/sites/config",

          "evaluationDelay": "AfterProvisioningSuccess",

          "existenceCondition": {

            "field": "Microsoft.Web/sites/config/minTlsVersion",

            "equals": "1.1"

          },

          "name": "web",

          "roleDefinitionIds": [

            "/providers/Microsoft.Authorization/roleDefinitions/de139f84-1756-47ae-9be6-808fbbe84772",

            "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"

          ],

          "deployment": {

            "properties": {

              "mode": "incremental",

              "parameters": {

                "siteName": {

                  "value": "[field('name')]"

                },

                "ipAddresses": {

                  "value": "[parameters('ipAddresses')]"

                }

              },

              "template": {

                "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",

                "contentVersion": "1.0.0.0",

                "parameters": {

                  "siteName": {

                    "type": "string"

                  },

                  "ipAddresses": {

                    "type": "array"

                  }

                },

                "resources": [

                  {

                    "type": "Microsoft.Web/sites/config",

                    "apiVersion": "2021-02-01",

                    "name": "[concat(parameters('siteName'), '/web')]",

                    "properties": {

                      "publicNetworkAccess": "Enabled",

                      "ipSecurityRestrictionsDefaultAction": "Deny",

                      "copy": [

                        {

                          "name": "ipSecurityRestrictions",

                          "count": "[length(parameters('ipAddresses'))]",

                          "input": {

                            "ipAddress": "[parameters('ipAddresses')[copyIndex('ipSecurityRestrictions')]]",

                            "action": "Allow",

                            "priority": "[add(100, copyIndex('ipSecurityRestrictions'))]",

                            "name": "[concat('ipRestriction_', copyIndex('ipSecurityRestrictions'))]"

                          }

                        }

                      ]

                    }

                  }

                ],

                "outputs": {}

              }

            }

          }

        }

      }

    },

    "parameters": {

      "effect": {

        "type": "String",

        "metadata": {

          "displayName": "Effect",

          "description": "Enable or disable the execution of the policy"

        },

        "allowedValues": [

          "DeployIfNotExists",

          "Disabled"

        ],

        "defaultValue": "DeployIfNotExists"

      },

      "ipAddresses": {

        "type": "Array",

        "metadata": {

          "displayName": "ipAddresses",

          "description": "List of IP addresses to allow access to the web app."

        },

        "defaultValue": [

          "198.51.100.0/24"

        ]

      }

    }

  }


Deployment using ARM template

 

We export the ARM template of an existing app service and modify the required parameters to deploy another app service with IP restrictions in place. However, the policy doesn’t allow the creation of an app service and is blocked with the same error message.


If we closely look at the policy rule of an IP restriction policy, it is checking the field Microsoft.Web/sites/siteconfig.

KrishnaM2265_3-1729591784350.png

 

But, the exported ARM template is using the field below.

KrishnaM2265_4-1729591784364.png

 

Similar to what Azure policy supports, we tried to define all these siteconfig attributes under Microsoft.Web/sites and tried to deploy the ARM template and removed that resource completely from the ARM template.

 

KrishnaM2265_5-1729591784379.png

 

KrishnaM2265_6-1729591784393.png

 

 

 

Deployment using Terraform

 

Once the IP restriction policy is in place, try to use the below azurerm providers to deploy the app service with IP restrictions enabled.

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_function_app --- Linux function app

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/windows_function_app ---Windows function app

We need to use the above modules to deploy the app service with the attributes below set for the app service or it must be supported.

KrishnaM2265_7-1729591784396.png

KrishnaM2265_8-1729591784400.png

KrishnaM2265_9-1729591784402.png

 

 

Disclaimer

  • Please note that products and options presented in this article are subject to change. This article reflects custom policy for enable ip restriction for app service in October 2024.
  • If users have the required permissions, they can create exemptions for their resources, which makes this policy ineffective for those resources.
  • It is highly recommended to test this policy in a non-production environment before applying it to your production environment to avoid any unintended disruptions and to make sure it meets your requirements.

 

 

References

https://learn.microsoft.com/en-us/azure/governance/policy/concepts/definition-structure-policy-rule#policy-functions 

Programmatically create policies - Azure Policy | Microsoft Learn

Troubleshoot common errors - Azure Policy | Microsoft Learn

Overview of Azure Policy - Azure Policy | Microsoft Learn

 

 

Published on:

Learn more
Azure Infrastructure Blog articles
Azure Infrastructure Blog articles

Azure Infrastructure Blog articles

Share post:

Related posts

Stay up to date with latest Microsoft Dynamics 365 and Power Platform news!
* Yes, I agree to the privacy policy