azure, Azure DevOps, Powershell

Azure : Add IP restriction rule to App Service using powershell script

Overview:

Azure Apps service has a feature which enables you to restrict user access to a web application using IP restriction feature.You can allow or deny the access to a set of IPs to your web app, using this feature.

You can find this option by clicking on Networking >Configure Access Restrictions .

NetworkingAppService

WhitelistIP

By default, it will apply the same restriction to the scm website as well.

Use Cases :

Below are the few use cases where you need to add IP restrictions.

  1. release agent IPs : When you automate the provisioning the azure resources through pipelines, sometimes, you need to white list the IP of the agent (the VM, in which the tasks are running) for running some tasks (for e.g. health check of website).
  2. Outbound IPs : When you have a web job associated with your web app, all the calls will be made by the outbound IP list available in the app service. In that case you need to white list the outbound IPs as well (Turning on Allow Azure IP option also works for this scenario).
  3. User IPs : If you want to provide access to different developers and testers, you need to white list their IPs.

You can run this powershell in your release pipeline once the web app is created. It will white list the IPs that you provide. You can add one pipeline variable to contain all the comma separated IP addresses and use that variable in the powershell task to pass the IPs to the script.

Parameters:

  1. RGName : Name of the Resource Group
  2. WebAppName : Name of the App Service
  3. priority :  Priority of the IP restriction(e.g: 1001)
  4. IPList : list of comma separated IPs which needs to be white listed

Script:

Script 1 :

Param
(
# Name of the resource group that contains the App Service.
[Parameter(Mandatory=$true)]
$RGName,

# Name of your Web or API App.
[Parameter(Mandatory=$true)]
$WebAppName,

# priority value.
[Parameter(Mandatory=$true)]
$priority,

# WhitelistIp values.
[Parameter(Mandatory=$true)]
$IPList,

# rule to add.
[PSCustomObject]$rule


)
function Add-AzureIpRestrictionRule
{
$ApiVersions = Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Web | 
Select-Object -ExpandProperty ResourceTypes |
Where-Object ResourceTypeName -eq 'sites' |
Select-Object -ExpandProperty ApiVersions

$LatestApiVersion = $ApiVersions[0]

$WebAppConfig = Get-AzureRmResource -ResourceType 'Microsoft.Web/sites/config' -ResourceName $WebAppName -ResourceGroupName $RGName -ApiVersion $LatestApiVersion

$WebAppConfig.Properties.ipSecurityRestrictions = $WebAppConfig.Properties.ipSecurityRestrictions + @($rule) | 
Group-Object name | 
ForEach-Object { $_.Group | Select-Object -Last 1 }

Set-AzureRmResource -ResourceId $WebAppConfig.ResourceId -Properties $WebAppConfig.Properties -ApiVersion $LatestApiVersion -Force 
}
$IPList= @($IPList-split ",")
Write-Host "IPList found "$IPList"."
$increment = 1
foreach ($element in $IPList)
{
if ($element -eq "" -OR $element -eq " ") {continue}
else
{
$element=$element.Trim()
$rule = [PSCustomObject]@{
ipAddress = "$($element)/32"
action = "Allow"
priority = "$priority"
name = "WhitelistIP"+ $increment}
$increment++
Add-AzureIpRestrictionRule -ResourceGroupName "$RGName" -AppServiceName "$WebAppName" -rule $rule
}
}
$OutboundIP = @(Get-AzureRmWebApp -Name "$WebAppName" -ResourceGroupName "$RGName").possibleOutboundIPAddresses -split ","
$increment = 1
foreach ($element in $OutboundIP)
{
$rule = [PSCustomObject]@{
ipAddress = "$($element)/32"
action = "Allow"
priority = "$priority"
name = "OutboundIP"+ $increment}
$increment++
Add-AzureIpRestrictionRule -ResourceGroupName "$RGName" -AppServiceName "$WebAppName" -rule $rule
}

This script is useful when you want to add less number of individual IP addresses.

If you have a large number of IP addresses, you can put them in a powershell script file(script 3) as a variable and call the below powershell file(script 2) which will add those IPs in the settings.

The reason we are using 2 powershell script is, script 4 may vary from one environment to other as it contains the list of IPs. So you may need to create multiple copies of script 3 based on environments (dev , test or prod). All those files can call script 2 to add the IPs to the access restriction rule. However, If you do not have any changes in list of IPs in any environment, you can put the “rules” custom object in script 2 itself and use it.

Sctipt 2:

Param(
[string]$WebAppName,
[string]$RGName,
[string]$resourceType='Microsoft.Web/sites/config',
[PSCustomObject] $rules
)

function AddRules($rules) {

$rules = @() 
$priority = 100
foreach ($item in $rules) {

$rule = [PSCustomObject]@{ ipAddress = $item.ipAddress ; priority = $priority }

$rules += $rule
$priority = $priority + 100
} 
return $rules 
}

$ApiVersions = Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Web |
Select-Object -ExpandProperty ResourceTypes |
Where-Object ResourceTypeName -eq 'sites' |
Select-Object -ExpandProperty ApiVersions

$LatestApiVersion = $ApiVersions[0]

# Registering IPs
Write-Host 'Registering IPs...'

$Settings = Get-AzureRMResource -ResourceName $WebAppName -ResourceType $resourceType -ResourceGroupName $RGName -ApiVersion $LatestApiVersion

$Settings.Properties.ipSecurityRestrictions = AddRules -rules $rules

Set-AzureRmResource -ResourceId $Settings.ResourceId -Properties $Settings.Properties -ApiVersion $LatestApiVersion -Force

Write-Host -ForegroundColor "Green" "IP range Added successfully!"

Script 3:

Param
(
# Name of the resource group that contains the App Service.
[Parameter(Mandatory=$true)]
$RGName,

# Name of your Web or API App.
[Parameter(Mandatory=$true)]
$WebAppName,

# subscriptionId value.
[Parameter(Mandatory=$true)]
$InputFile
)
[PSCustomObject]$rules = 
@{ipAddress = "XXX.XX.2.XXX/32"},`
@{ipAddress = "XXX.XX.2.XXX/32"},`
@{ipAddress = "XX.XXX.XX.XXX/32"},`
@{ipAddress = "XXX.X.3X.22X/32"},`
@{ipAddress = "2X3.22X.XXX.XXX/32"},`
@{ipAddress = "2X3.22X.XXX.XXX/32"},`
@{ipAddress = "XXX.XX.2.XX/32"},`
@{ipAddress = "2X3.22X.XXX.XXX/32"},`
@{ipAddress = "2XX.XXX.XXX.XXX/32"},`
@{ipAddress = "2XX.X2X.XXX.2XX/32"},`
@{ipAddress = "XX.X2.XX.XX/32"},`
@{ipAddress = "XX.3X.X2X.2X2/32"},`
@{ipAddress = "XX.33.2XX.XX3/32"},`
@{ipAddress = "XX.XX.XX.2X3/32"},`
@{ipAddress = "X3.XX.X.XXX/32"},`
@{ipAddress = "2X2.XXX.X2.XX/32"},`
@{ipAddress = "2XX.X2X.XX.XXX/32"},`
@{ipAddress = "XX.XXX.X2X.XX/32"}

Write-Host 'PRODUCTION SLOT IPs...'
& $InputFile -WebAppName $WebAppName -resourceGroupName $RGName -rules $rules 
Write-Host 'STAGING SLOT IPs...'
& $InputFile -WebAppName $WebAppName/Staging -resourceGroupName $RGName -rules $rules -resourceType Microsoft.Web/sites/slots/config

This is just a demo. You may need to change your script based on your need. Hope it helps. Happy learning. 🙂 

 

 

azure, Azure DevOps

Azure DevOps : Build and publish your project to userdefined folder using MSBuild task in build pipeline

Overview :

In most of the cases the solution of your application contains more than one project for example one or more web app, function app, WCF service, web API. When you build the solution you will get the predefined folder structure in the artifact. But sometime you might need to publish the different project to some user defined folder structure rather than the default folder structure. 

In this article we will discuss how you can have complete control over where you want your projects to be placed while publishing the code.

Solution:

  • Add the MSBuild task in your build pipeline if , either you have not one already or you have one MSBuild task which builds you whole solution.
  • Select the necessary settings in the new task as shown below. In the project tab you need to select the project that you want to build separately and publish to a different folder.

 

1

 

  • Use $(BuildConfiguration) in the Configuration section. 

2

  • BuildConfiguration can be configured in the variable section as per the need. 

3

  • MSBuild Arguments field is the one which will help you publishing your code to the folders that you want. Put the below mentioned setting in the MSBuild Arguments section.
/p:WebProjectOutputDir="$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\WebAPIs\WebAPIExample1"
/p:OutputPath="$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\WebAPIs\WebAPIExample1\bin"

Below is the screenshot for your reference.

4

  • Build.ArtifactStagingDirectory is the predefined build variable which stores the local path on the build agent where any artifacts are copied to before being pushed to their destination. For example: c:\agent_work\1\a 

You can publish different project into different user defined folder by following the above mentioned steps. But what happens when the folder you want, is not part of the solution. For example if your SQL scripts or power shell scripts are not part of the solution but you need them in your artifact, you can achieve that as well. It is discussed in detail in my next article. 

Happy learning . 🙂