Com And Hosting

Securing Azure Storage Account

It is recommended to lock down the Azure Storage Account where possible especially when storing sensitive data. You can allow vnet to access the storage account so that other Azure resources can access the storage account seamlessly. Alternatively, use the private endpoint to connect the Storage account from Data Factory or other integration services.

You can enable the Firewall for a storage account from Azure Portal under the network settings. See the screenshot below. Add the ip address in the firewall rule to allow access to the storage account.

Accessing a storage account from Azure DevOps CI/CD pipeline to deploy storage account components e.g. Storage Tables, Blobs, etc can become challenging because you need to allow the agent IP address to the storage account firewall rule. Otherwise, the pipeline will fail and throw an access denied error when trying to deploy storage account components through CI/CD automation. Azure DevOps agent has a huge IP range and changes every fortnight according to Microsoft. Now you can download the IP addresses from https://www.microsoft.com/en-us/download/details.aspx?id=56519 and add them to the Storage Account firewall rule. This can be tedious work when we like to make jobs easy with automation and less manual intervention.

In this example, I will show you how to integrate your Azure DevOps pipeline to add the agent IP address during the deployment using the Just In Time (JIT) approach and remove the IP address from the firewall once the deployment is complete.

 

Azure CI/CD Pipeline

You have a typical CI/CD pipeline with stages, jobs, steps, and tasks to deploy code in a different environment. So, assuming you’re deploying an ARM template using Powershell scripts with parameters file. Create a task to execute the PowerShell script file in the YML file like below.

steps:
- task: AzurePowerShell@5
  displayName: 'AzureDeployment'
  inputs:
    azureSubscription: 'az-subscription-01'
    pwsh: true
    scriptType: 'filepath'
    scriptPath: 'deploy.ps1'
    azurePowerShellVersion: 'LatestVersion'

 

Now create a PowerShell file name deploy.ps1 and add the following scripts.

# Add the agent IP to the storage firewall

$resourceGroupName ="MyResourceGroup1" 
$storageAccountName ="stdata0123"

$ipaddress =(Invoke-WebRequest http://ipinfo.io/ip).Content
 
Write-Host "Agent IP address: " 
$ipaddress Write-Host "Adding IP $ipaddress to the firewall ..." 

Add-AzStorageAccountNetworkRule -ResourceGroupName $resourceGroupName -Name $storageAccountName -IPAddressOrRange $ipaddress Start-Sleep -Seconds 40 

## your other code goes here to add or modify the storage account component

In the above code, first set up the Azure Resource Group and Storage Account name variables. Invoke a web request to get the DevOps agent IP address. Once you get the IP address, add the IP address to the Storage Account Firewall role. Before you execute the other codes, you noticed I put 40 seconds of sleep because the Firewall update may take a few seconds on the Azure portal to propagate.

Now every time you run the DevOps pipeline it will add the agent IP address automatically to the firewall rule that will allow you to deploy the resources on the storage account.

Since the DevOps agent has a huge IP range, the list can grow fast depending on the number of deployments you do. So, to make it even better we can execute another PowerShell command to remove the IP address once the deployment is complete.

To do that, we first need to get all the IP addresses from the Storage Account IPRules and store them in an array. We can than iterate through the list and remove when the IP matches with the current Agent IP. See the code sample below.

 

# Add the agent IP to the storage firewall

$resourceGroupName ="MyResourceGroup1" 
$storageAccountName ="stdata0123"

$ipaddress =(Invoke-WebRequest http://ipinfo.io/ip).Content

Write-Host "Agent IP address: " $ipaddress

Write-Host "Adding IP $ipaddress to the firewall ..."
Add-AzStorageAccountNetworkRule -ResourceGroupName $resourceGroupName[$environment] -Name $storageAccountName[$environment] -IPAddressOrRange $ipaddress

Start-Sleep -Seconds 40

try {
    ## Do your stuff here
   ##
}
catch [System.Management.Automation.MethodInvocationException] {
    # Write the error on the screen when an exception happens
    Write-Host "An error occurred:"
    Write-Host $_

}
finally {
   # Remove the IP address from the storage account.
    $rules = (Get-AzStorageAccountNetworkRuleSet $resourceGroupName -Name $storageAccountName).IpRules
    foreach ($rule in $rules) {

        if($ipaddress -eq $rule.ipAddressOrRange) {

            # Remove the IP Address from the firewall
            Remove-AzStorageAccountNetworkRule -ResourceGroupName $resourceGroupName -Name $storageAccountName -IPAddressOrRange $ipaddress
            Write-Host "IP Address: " $rule.ipAddressOrRange " has been removed from the firewall" 
        }
    }
}

Hope this helps DevOps engineers!

Leave a Reply

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