This challenge is regarding Azure and Azure DevOps but I would imagine this happening on similar platforms (AWS, GCP, Github, Gitlab, etc.)
I am currently using Azure DevOps Pipelines but I am facing a problem with interacting with resources behind firewalls (either IP restricted or virtual network restricted). As Azure Pipeline spins up a new VM it requires me to whitelist that given public IP for that newly spun up machine each time I do a run. It is very janky to accommodate for this whitelisting as I am creating Azure Pipelines as submodules for reproducibility purpose extending templates from one project and using it in multiple. Terraform state needs to access configurations on restricted resources, hence throwing access denied messages.
I have looked into the following to solve the challenge and my thoughts about them:
Implementing Azure Virtual Machine scale-set agents instead of Microsoft Hosted agent (https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/scale-set-agents?view=azure-devops).
This would require a long discussion with our security team as they are not fan of using virtual machines in the cloud.
Deploy Atlantis on AKS with a static public IP from the Load Balancer and whitelist this one IP (https://learn.microsoft.com/en-us/azure/aks/static-ip).
This would require some initial setup from my side as I could not find that much documentation on deploying this using Azure (AKS) and Azure DevOps. (found this article: https://engineering.plex.com/posts/deploying-infrastructure-azure/ and this video using Github https://www.youtube.com/watch?v=33j49_n8Zvc&ab_channel=JJAsghar. Terraform Module for deploying Atlantis on AWS: https://github.com/terraform-aws-modules/terraform-aws-atlantis)
Use Terraform Enterprise for infrastructure deployment and whitelist Terraform Enterprise IP range (https://www.terraform.io/docs/cloud/api/ip-ranges.html).
This would require introducing a new platform for provisioning infrastructure.
Make a huge whitelist stage that whitelists each resource from my Terraform Module Registry depending on the module used in the pipeline (very cumbersome to maintain).
This would require too much maintenance and does not seem like the best solution.
What are your thoughts on solving this challenge?
You can use scripts to get the ip of the cloud agents. And dynamically whitelist the ip address for your azure storage account using Azure PowerShel or Azure Cli. See below example:
1, Add Azure Powershell task before Terraform
task in your azure devops pipeline to get the agent's ip address and add whitelist for azure storage account.
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: InlineScript copy'
inputs:
azureSubscription: 'Microsoft-Azure'
ScriptType: InlineScript
Inline: |
$ip = Invoke-RestMethod http://ipinfo.io/json | Select -exp ip #get agent ip
#add ip to whitelist
Add-AzStorageAccountNetworkRule -ResourceGroupName "myresourcegroup" -AccountName "mystorageaccount" -IPAddressOrRange $ip
azurePowerShellVersion: LatestVersion
2, Add another azure powershell task at the end of your pipeline to remove the whitelist.
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: InlineScript copy'
inputs:
azureSubscription: 'Microsoft-Azure'
ScriptType: InlineScript
Inline: |
$ip = Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
Remove-AzStorageAccountNetworkRule -ResourceGroupName "myresourcegroup" -AccountName "mystorageaccount" -IPAddressOrRange $ip
azurePowerShellVersion: LatestVersion
Check document here for more information.
The IP ranges for cloud agents changes weekly. You can also check the weekly file and update the whitelist ip address manually. Check here for more information.
Related
I am trying to run a terraform deployment that deploys a storage container. The initial deployment works (due to no IP filtering yet being in place), but subsequent fail. When running terraform plan I am getting the following:
Error: retrieving Container "xxxx" (Account "xxxx" / Resource Group "xxx"): containers.Client#GetProperties: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="AuthorizationFailure" Message="This request is not authorized to perform this operation.\nRequestId:62a85c92-901e-0021-12de-816608000000\nTime:2022-06-17T00:11:56.2063816Z"
From some research and debugging this happens when the storage container does not have the IP of the hosted pipeline agent whitelisted.
I have modified my pipeline so that the IP of the agent is retrieved and added as a firewall rule. I have then added sleeps of various times (up to 5 minutes) to try and give time for the rule to take affect, but it never works.
Here is a snippet of my pipeline:
- task: AzureCLI#2
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
agentIP=$(curl -s https://api.ipify.org/)
az storage account network-rule add -g xxx --account-name xxx --ip-address $agentIP
sleep 300
During the sleep period I have confirmed that the agent IP is added to the whitelist. The whitelisting is also done within the same stage as the terraform plan.
Is anyone able to advise as to where I might be going wrong?
EDIT
I have taken this a step further and added a step in my pipeline to whitelist all IP addresses in my DevOps Organization Region (114 ranges) and it still fails.
And the IP my Azure DevOps pipeline agent gets is not even part of the ranges returned by az network list-service-tags --location australiaeast --query "values[?name == 'AzureCloud.australiaeast'].properties.addressPrefixes[]"
To resolve the error "Status=403 Code=AuthorizationFailure Message=This request is not authorized to perform this operation" try to modify setting in Azure Portal like below:
Go to Azure Portal -> Storage Accounts -> Your Storage Account you have created from terraform -> Networking
Enabling "Allow trusted Microsoft services to access this storage account" allows you to access storage account.
Make sure to have the required permissions like Contributor and User Access Administrator roles / Storage Blob Data Owner role.
If still the issue persists, make use of the sample code in this similar SO Thread by Ansuman Bal.
What I ended up doing was grabbing the build agent IP when build initiates on the DevOps pipeline (just initiate a call to https://api.ipify.org?format=json to get the build agent IP), and then adding that IP to the list of Network Rules on the storage account (if it exists) using powershell/AzCli, and then also ensure IP is added to the network rules in your bicep/arm/terraform. That seems to work fine.
I'm trying to access an azure blob storage account to write some files from my pipeliens running with azure devops hosted agent.
We can't use yet the azure devops service tag with azure devops hosted agent
And I was wondering if there is a smart solution to access my blob storage from my hosted agents without opening it to all the internet.
Thank you in advance guys
Based on your requirement, you need to access Private Storage account with Microsoft-hosted agent.
As far as I know, service tag is not currently supported by Azure Storage account when setting Firewall.
To meet your requirements, you can use script to get the current Microsoft-hosted agent IP and add it to Azure Storage account firewall whitelist with Azure CLI or Azure PowerShell.
For example:
steps:
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: Set Rule'
inputs:
azureSubscription: kevin0215
ScriptType: InlineScript
Inline: |
$IP= Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
$IP
Add-AzStorageAccountNetworkRule -ResourceGroupName "ResourceGroup" -AccountName "kevin0204" -IPAddressOrRange "$IP"
preferredAzurePowerShellVersion: ' 3.1.0'
- task: AzureFileCopy#4
displayName: 'AzureBlob File Copy'
inputs:
SourcePath: test
azureSubscription: kevin0322
Destination: AzureBlob
storage: test
ContainerName: 1
- task: AzurePowerShell#5
displayName: 'Azure PowerShell script: Remove Rule'
inputs:
azureSubscription: kevin0215
ScriptType: InlineScript
Inline: |
$IP= Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
$IP
Remove-AzStorageAccountNetworkRule -ResourceGroupName "ResourceGroup" -AccountName "kevin0204" -IPAddressOrRange "$IP"
preferredAzurePowerShellVersion: ' 3.1.0'
Explanation:
You can add the IP to the firewall whitelist before uploading the file. After uploading, you can delete this IP.
Note::The current azure storage account has a known limitation. Refer to this doc: Limitations of Azure Storage Account IP network rules.
When your Azure Devops Service organization and Azure Storage Account are in the same region, they will be accessed through private ip. This can cause intermittent access issues.
I created a resource group and various resources inside it. In Resources I have ADF & Pipelines, SQL Server, DBs & Objects, Logics Apps, AAS Models, Storage Accounts etc.
Now I want to check-in all my information into source control for versioning. I have Azure Devops as well. My need is that I want to deploy the resources and objects into another environment.
e.g I have a dev environment. I created all resources in a resource group. I did not use any template or source control while building this environment. I got Azure DevOps now. Now I want to built the test set up from the dev environment. How do I achieve this?
Any help is appreciated. Thank you.
You can first export the Template from your Azure resource group portal. See below:
1, Go to Azure Resource Group portal-->Click Export template under Automation-->Download
You can also use Az cli/Azure powershell to export the template. See example commands here
Please check the documents here to learn more about how to manage your azure resource using ARM Template.
2, Sync the ARM template downloaded in above step to your azure repo.
3, Create an azure Resource Manager service connection to connect your Azure subscription to Azure devops. See this thread for an example.
4, Create an azure devops pipeline to automate the azure resource deployment.
5, Add Azure Resource Manager (ARM) Template Deployment Task in your azure pipeline to deployment the template exported in the first step.
steps:
- task: AzureResourceManagerTemplateDeployment#3
displayName: 'ARM Template deployment: Resource Group scope'
inputs:
azureResourceManagerConnection: 'azuresubscriptionServiceConnection'
subscriptionId: '......'
resourceGroupName: 'Resource-group'
location: 'East US'
csmFile: template.json
csmParametersFile: parameters.json
Above just gives you the general steps you need to take when deploying azure resources via azure devops pipeline. You need to explore the documents for yourself to learn how to customize your pipeline, how to create ARM template, And how to use the AzureResourceManagerTemplateDeployment task.
I have a Pipeline in Azure DevOps that should build and push a Docker image to an Azure Container Registry. Therefore I have a service connection (type: docker registry) in place in order to authorize the pipeline to push. If I remove the network restriction in the container registry everything goes just fine.
As soon as I want to restrict the network access it does not work anymore and I get a "denied" in the pipeline output of the docker task. I also tried to add the Azure DevOps IP ranges (13.107.43.0/24, 13.107.42.0/24, 13.107.9.0/24, 13.107.6.0/24).
Any idea what is wrong?
Actually, all the tasks run in the agents when you use the Pipeline. And the network of the agents, you can take a look here. As you see you need to allow the IP addresses of the agents, and the IP ranges vary over time. Every week you need to add the new IP addresses in the firewall rules for your organization region. So it's a little troublesome.
Compare with control the access IP address, I recommend you control the permission of the credential of the ACR. If a person does not have enough permission, he can't do the things required special permission even if he can access the ACR. Here are the details about the permission oo ACR.
you could add the agent IP dynamically in the pipeline before the push, and do an equivalent remove afterwards:
- task: AzureCLI#2
inputs:
azureSubscription: $(ACR_SERVICE_CONNECTION_NAME)
scriptType: pscore
scriptLocation: inlineScript
inlineScript: |
# Open firewall on ACR for IP of current agent
$agentIp = (New-Object net.webclient).downloadstring("http://checkip.dyndns.com") -replace "[^\d\.]"
az acr network-rule add -n YourACRName--ip-address $agentIp
Hi and thanks for taking the time to look at my question.
I'm using terraform to create an api_management object in Azure. I've mastered the setup of API's, Products, Policies, Subscriptions and Users.
My devs setup an authorisation server on the API Management object in Azure, which I automated using azurerm_api_management_authorization_server which works fine.
However, I can't see how in terraform I can configure the API settings to use that authorisation server.
API User Authorisation Settings
Looks as if this capability is currently not available via Terraform, which can be found by the open issue against the azurerm provider:
https://github.com/terraform-providers/terraform-provider-azurerm/issues/3341
What I would recommend doing to let you continue building out your infrastructure within Terraform, would be to utilise the azurerm_template_deployment resource.
This would let you utilise the available ARM API's from an ARM deployment:
https://learn.microsoft.com/en-us/azure/templates/microsoft.apimanagement/2019-01-01/service/apis
Sadly, until that issue is closed that capability won't be in the azurerm provider.
Note to the Answer provided by Lachie White
As I'm running this from a yaml pipeline in azure devops, I got around this limitation by using an azure powershell task
- task: AzurePowerShell#5
inputs:
azureSubscription: 'Subscription (111111111-1111-1111-1111-111111111111)'
ScriptType: 'InlineScript'
Inline: |
$ApiMgmtContext = New-AzApiManagementContext -ResourceGroupName "api-mgmt-rg" -ServiceName "api-mgmt"
$ApiAuthorizationServer = Get-AzApiManagementAuthorizationServer -Context $ApiMgmtContext
$ApiAuthorizationServerName = $ApiAuthorizationServer.Name
Set-AzApiManagementApi -Context $ApiMgmtContext -ApiId "api-name" -AuthorizationServerId "$ApiAuthorizationServerName"
azurePowerShellVersion: 'LatestVersion'