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, которая обязательно будет расположена в виртуальной сети. Таким образом, вы можете добавить виртуальную сеть в белый список брандмауэра хранилища ключей.


На самом деле, я не думаю, что вам это нужно. Потому что никто не может получить доступ к вашему хранилищу ключей без политики доступа. Так что теоретически это достаточно безопасно.

Но если вам необходимо защитить свое хранилище ключей с помощью брандмауэра и сетевых правил, вы можете использовать собственный агент.

Другие вопросы по тегам