If you are deploying Azure infrastructure using Micorosft hosted Azure pipeline agents you may have to whitelist Microsoft hosted agent IP adress in resources such as storage account where you keep your terraform state, or the key vaults, if you add update secrets to the key vault via terraform and if such resouces are network protected within a vNet in Azure. If the IP is not whitelisted there will be access issue and piplines would fail to make required updates. Let's look at two steps we can implement to add agent IP to a state storage and key vault, and then remove the IP once tarraform plan or apply is done.
Expectation is to execute two tasks as shown below in the pipeline job.
Below is the task in Azure pipeline using poweshell core, which can be used with Azure CLI task, to add IP of the hosted build agent to KV and a storage account. Here we use url https://api.ipify.org/ to get the IP of the Azure pipeline agent. Then we apply to storage and the key vault. The task will verify if the keyvault is available before adding IP, so it will not fail in the intial run where the key vault is not available.
parameters: - name: serviceconnection type: string steps: - task: AzureCLI@2 displayName: 'Apply agent IP to Azure resources' inputs: azureSubscription: '${{ parameters.serviceconnection }}' scriptType: pscore scriptLocation: inlineScript inlineScript: | $rgName = "$(resource_name_prefix)-rg"; $kvName = "$(resource_name_prefix)-kv"; $StateRgName = "$(prefix)-shared-state-rg"; $stateStorageAccountName = "$(prefix)$(environment)tfstatesa01"; $subscriptionId = "$(subscription_id)"; $managementSubscriptionId = "$(management_subscription_id)"; $publicIp = (Invoke-WebRequest -uri "https://api.ipify.org/").Content.Trim(); echo "Applying agent public IP $publicIp to state storage account $stateStorageAccountName in RG $StateRgName ..."; az storage account network-rule add --account-name $stateStorageAccountName --resource-group $StateRgName --ip-address "$publicIp" --subscription $managementSubscriptionId $groups = az group list --subscription $subscriptionId | ConvertFrom-Json if (($groups.name -ne $null) -and ($groups.name.Contains($rgName))) { echo "RG $rgName found. Searching for KV $kvName ..."; $kvs = az keyvault list -g $rgName --subscription $subscriptionId | ConvertFrom-Json if (($kvs.name -ne $null) -and ($kvs.name.Contains($kvName))) { echo "KV $kvName found. Applying agent public IP $publicIp to KV ..."; az keyvault network-rule add --name $kvName --resource-group $rgName --ip-address "$publicIp/32" --subscription $subscriptionId } else { echo "KV $kvName not found."; } } else { echo "RG $rgName not found."; } Start-Sleep -Seconds 30
Then we can have a task that is running always, even if terraform steps fail it wil ensure to remove the added IP of the pipeline agent from the resources. Below task remove only the agent IP if it exist in the storage or in the key vault.
parameters: - name: serviceconnection type: string steps: - task: AzureCLI@2 condition: always() displayName: 'Remove agent IP from Azure resources' inputs: azureSubscription: '${{ parameters.serviceconnection }}' scriptType: pscore scriptLocation: inlineScript inlineScript: | $rgName = "$(resource_name_prefix)-rg"; $kvName = "$(resource_name_prefix)-kv"; $StateRgName = "$(prefix)-shared-state-rg"; $stateStorageAccountName = "$(prefix)$(environment)tfstatesa01"; $subscriptionId = "$(subscription_id)"; $managementSubscriptionId = "$(management_subscription_id)"; $publicIp = (Invoke-WebRequest -uri "https://api.ipify.org/").Content.Trim(); $storageRules = az storage account network-rule list --account-name $stateStorageAccountName --resource-group $StateRgName --subscription $managementSubscriptionId | ConvertFrom-Json if(($storageRules.ipRules -ne $null) -and ($storageRules.ipRules.ipAddressOrRange -ne $null) -and ($storageRules.ipRules.ipAddressOrRange.Contains("$publicIp"))) { echo "Agent public IP $publicIp is available in state storage account $stateStorageAccountName in RG $StateRgName. Deleting Agent public IP $publicIp ..."; az storage account network-rule remove --account-name $stateStorageAccountName --resource-group $StateRgName --ip-address "$publicIp" --subscription $managementSubscriptionId } else { echo "Agent public IP $publicIp is not available in state storage account $stateStorageAccountName in RG $StateRgName." } $groups = az group list --subscription $subscriptionId | ConvertFrom-Json if (($groups.name -ne $null) -and ($groups.name.Contains($rgName))) { echo "RG $rgName found. Searching for KV $kvName ..."; $kvs = az keyvault list -g $rgName --subscription $subscriptionId | ConvertFrom-Json if (($kvs.name -ne $null) -and ($kvs.name.Contains($kvName))) { echo "KV $kvName found. Checking if agent public IP $publicIp is available in KV ..."; $rules = az keyvault network-rule list --name $kvName --resource-group $rgName --subscription $subscriptionId | ConvertFrom-Json if(($rules.ipRules -ne $null) -and ($rules.ipRules.value -ne $null) -and ($rules.ipRules.value.Contains("$publicIp/32"))) { echo "Agent public IP $publicIp is available in KV $kvName. Deleting Agent public IP $publicIp ..."; az keyvault network-rule remove --name $kvName --resource-group $rgName --ip-address "$publicIp/32" --subscription $subscriptionId } else { echo "Agent public IP $publicIp is not available in KV $kvName." } } else { echo "KV $kvName not found."; } } else { echo "RG $rgName not found."; }
No comments:
Post a Comment