Azure DevOps Build Pipeline не может получать секреты из Key Vault при защите с помощью vnet и брандмауэра
Невозможно получить секреты из Key Vault, если оно защищено vnet и брандмауэром.
Я хотел бы использовать секреты, хранящиеся в хранилище ключей, из задачи DevOps Build Pipeline, и я хотел бы тщательно следовать передовым методам безопасности и защиты. В качестве передового метода безопасности я хочу, чтобы хранилище ключей было доступно из выбранных виртуальных сетей, выбранных служб Azure и доверенных IP-адресов в Интернете. Конечно, я бы использовал субъект-службу и соответствующие разрешения (список / получение).
К сожалению, Azure DevOps не входит в число надежных служб. Итак, моя альтернатива - занести в белый список IP-адреса DevOps. Я обнаружил, что мой DevOps находится в регионе Восток США 2, и я загрузил IP-адреса Azure Datacenter (отфильтрованные с Востоком США 2). На востоке США 2 насчитывается около 285 IP-адресов. Брандмауэр Key Vault имеет ограничение на количество правил брандмауэра, которое вы можете добавить, и оно составляет 127! Итак, мне не повезло!
На данный момент я могу получить секреты из хранилища ключей в конвейере сборки, только если я разрешаю все сети! Да, мне все еще нужно пройти аутентификацию, чтобы получить секреты, но я проиграл в глубокой защите. Мне действительно нужно заблокировать хранилище ключей для доверенных сетей, но я не могу. Почему? Я не могу добавить более 127 правил брандмауэра (для охвата региона), а DevOps не является одной из надежных служб Azure!
3 ответа
Я подумал, что добавлю к этому изюминку решения, которое предоставил Prodip. Этот основан на том факте, что когда вы запрашиваете секрет, клиент az достаточно любезен, чтобы сообщить вам, какой у вас IP-адрес клиента, то есть:
az keyvault secret show -n "a-known-client-secret" --vault-name "$keyVaultName"
Attempting to get value for known secret from key vault: '******'
ERROR: Client address is not authorized and caller is not a trusted service.
Client address: 1.1.1.1
Caller: appid=***;oid=****;iss=https://sts.windows.net/***/
Vault: ******;location=******
Итак, вот мой сценарий bash (whitelist-agent-for-key-vault.sh):
#!/usr/bin/env bash
## By default the Azure DevOps IP addresses are NOT whitelisted for key vault access. So even if the service principal has access, you won't get past the firewall.
## The solution is to temporarily add the build agent IP address to the key vault firewall, and remove it when the pipeline is complete.
if [[ $(uname -s) == "Linux" ]]; then
azcmd="az"
else
# If we're in a bash shell on Windows, az commands don't work, but we can call the az.cmd batch file directly from git Bash if we can find it...
azcmd=$(where az.cmd)
fi
# Are we removing rather than setting?
if [[ $1 == "-r" ]]; then
if [[ -z "$3" ]]; then
echo "Build agent IP address is empty, no whitelist entry to remove from key vault: '$2'"
else
echo "Removing key vault '$2' network rule for DevOps build agent IP address: '$3'"
# Remember to specify CIDR /32 for removal
"$azcmd" keyvault network-rule remove -n $2 --ip-address $3/32
fi
exit 0
fi
keyVaultName=$1
########################################################################
##### This is the known secret which we request from the key vault #####
########################################################################
knownSecret="<My known secret>"
echo "Attempting to get value for known secret from key vault: '$keyVaultName'"
# Attempt to show secret - if it doesn't work, we are echoed our IP address on stderror, so capture it
secretOutput=$("$azcmd" keyvault secret show -n "$knownSecret" --vault-name "$keyVaultName" 2>&1)
buildAgentIpAddress=$(echo $secretOutput | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
set -euo pipefail
if [[ ! -z "$buildAgentIpAddress" ]]; then
# Temporarily whitelist Azure DevOps IP for key vault access.
# Note use of /32 for CIDR = 1 IP address. If we omit this Azure adds it anyway and fails to match on the IP when attempting removal.
echo "Azure DevOps IP address '$buildAgentIpAddress' is blocked. Attempting to whitelist..."
"$azcmd" keyvault network-rule add -n $keyVaultName --ip-address $buildAgentIpAddress/32
# Capture the IP address as an ADO variable, so that this can be undone in a later step
echo "##vso[task.setvariable variable=buildAgentIpAddress]$buildAgentIpAddress"
else
# We didn't find the IP address - are we already whitelisted?
secretValue=$(echo $secretOutput | grep -o "value")
if [[ -z "$secretValue" ]]; then
echo "Unexpected response from key vault whitelist request, json attribute 'value' not found. Unable to whitelist build agent - response was: '$secretOutput'"
exit 1
fi
fi
Вот как я добавляю IP в белый список:
# Add agent IP to key vault white list
- task: AzureCLI@2
displayName: Add Azure DevOps build agent IP to key vault white list
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
scriptType: bash
scriptLocation: scriptPath
scriptPath: $(Pipeline.Workspace)/server-build-tools/drop/build-scripts/whitelist-agent-for-key-vault.sh
arguments: '$(keyVaultName)'
Вот как я удаляю IP из белого списка
- task: AzureCLI@2
displayName: Remove Azure DevOps build agent IP from key vault white list
condition: always()
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
scriptType: bash
scriptLocation: scriptPath
scriptPath: $(Pipeline.Workspace)/server-build-tools/drop/build-scripts/whitelist-agent-for-key-vault.sh
arguments: '-r "$(keyVaultName)" "$(buildAgentIpAddress)"'
Предостережения:
- Это зависит от того, что субъекту службы Azure DevOps был предоставлен доступ для чтения к секретам хранилища ключей.
- Заменить
knownSecret
значение с именем вашего известного секрета
Бонус:
Это работает с использованием Azure CLI и было протестировано в Azure DevOps для Linux и агентов сборки Windows, работающих под Git bash для последнего. Обычно, если вы пытаетесь запустить команды "az" в Git Bash, вы просто получаете "Команда не найдена". Мне нужно было решение, которое работало бы на обоих, поскольку мне нужно делиться кодом из-за требований сборки Linux / Windows.
Вы можете добавить шаг в определение сборки, чтобы внести IP-адрес агента в белый список, а затем удалить его из белого списка в конце сборки. Это не решение, а обходной путь, пока группа разработчиков продукта Azure не добавит Azure DevOps в качестве доверенной службы. Спасибо @DanielMann за идею.
Решение простое, но я не собирался доверять ipify.org как конечной точке REST API для получения IP-адреса моего агента сборки. Вместо этого я создал свою собственную (и надежную) службу в Azure Function- GetClientIP. DevOps - это не моя повседневная работа, и мне было трудно понять, как назначать и использовать пользовательские переменные и передавать их следующему шагу / задаче / этапу в конвейере! Документация Microsoft по использованию переменных не помогла мне достаточно, но я понял это после множества неудачных запусков!
См. Полное решение в моем блоге - Azure DevOps Build Pipeline - используйте ключи и секреты из Key Vault.
Единственное решение - использовать собственный агент.
Вы можете создать виртуальную машину и установить в нее агент-клиент. Затем вы можете добавить новый агент в пул агентов DevOps и использовать его.
Поскольку самоагент работает на вашей виртуальной машине Azure, которая обязательно будет расположена в виртуальной сети. Таким образом, вы можете добавить виртуальную сеть в белый список брандмауэра хранилища ключей.
На самом деле, я не думаю, что вам это нужно. Потому что никто не может получить доступ к вашему хранилищу ключей без политики доступа. Так что теоретически это достаточно безопасно.
Но если вам необходимо защитить свое хранилище ключей с помощью брандмауэра и сетевых правил, вы можете использовать собственный агент.