The problem, as you may have encountered, is the IP not only changes each run, but also changes each week.
This was a problem for us because we needed to add the whitelist of these IP's to our security group in Terraform so the pipeline could SSH into our container and deploy. We did look at using something like the above which was getting the IP from the machine by calling a 3rd party and storing as a var, but this was tricky since we needed to apply this in Terraform
More problems include:
- URL for downloading the IP address from Microsoft changes each time. So its hard to point to a static URL
- Looping through the IPs and making the data readable for terraform required a bit of horrible replacing and splitting
- Also worth noting, data from external data is not really designed for being used like this, so proceed with caution.
If you or anyone is using Terraform, this is what we came up with:
terraform/.../security.tf
data "external" "azure_devops_ip_ranges" {
program = ["bash", "${path.root}/../azure_devops_get_ip_ranges.sh"]
}
resource "...._security_group" "azuredevops" {
name = "azuredevops"
description = "access from azuredevops"
}
resource "...._security_group_rules" "azuredevops" {
security_group_id = ...._security_group.azuredevops.id
## had to increase the timeout here because the amount of IPs from Azure Devops was in the hundreds and it took time
timeouts {
create = "15m"
update = "15m"
delete = "5m"
}
## So yep, this looks a little ugly. We get the data from the external call with data.external.azure_devops_ip_ranges.result.ips. Then replace quotes with nothing so its just the IPs.
## Then split over a new line
ingress {
protocol = "TCP"
ports = ["22"]
cidr_list = split("\n", replace(data.external.azure_devops_ip_ranges.result.ips, "\"", ""))
}
}
terraform/azure_devops_get_ip_ranges.sh
#!/bin/bash
## Scrape the download page for the download link
DOWNLOAD_LINK=$(curl -sS https://www.microsoft.com/en-us/download/confirmation.aspx\?id\=56519 | egrep -o 'https://download.*?\.json' | uniq)
## curl the download link and use jq to get the IPs we need. For pipelines you need AzureCloud and our region was uksouth
IPS=$(curl ${DOWNLOAD_LINK} | jq '.values[] | select(.name=="AzureCloud.uksouth") | .properties.addressPrefixes'[])
## because using external data in terraform expects JSON, output JSON
jq -n \
--arg ips "$IPS" \
'{"ips":$ips}'
Hope this can help someone