繁体   English   中英

使用 vnet 和防火墙保护时,Azure DevOps Build Pipeline 无法从 Key Vault 获取机密

[英]Azure DevOps Build Pipeline can't get secrets from Key Vault when secured with vnet and firewall

当使用 vnet 和防火墙保护时,无法从 Key Vault 获取机密。

我想使用 DevOps Build Pipeline 任务中存储在 Key Vault 中的秘密,我想遵循安全最佳实践和深度防御。 作为安全最佳实践,我希望可以从选定的虚拟网络、选定的 azure 服务和受信任的 Internet ip 访问密钥保管库。 当然,我会使用服务主体和适当的权限(列表/获取)。

不幸的是,Azure DevOps 不是值得信赖的服务之一。 因此,我的替代方案是将 DevOps IP 列入白名单。 我发现我的 DevOps 位于美国东部 2 区域,我下载了 Azure 数据中心 IP(使用美国东部 2 过滤)。 US East 2 大约有 285 个 IP。Key Vault 防火墙对您可以添加的防火墙规则数量有限制,它是 127 个! 所以,我倒霉了!

目前,只有在我允许所有网络的情况下,我才能在构建管道中从密钥保管库中获取机密! 是的,我仍然需要通过身份验证才能获得秘密,但我在纵深防御上失败了。 我真的需要将密钥保管库锁定到受信任的网络,但我不能。 为什么? 我添加的防火墙规则不能超过 127 个(覆盖该区域),而且 DevOps 不是值得信赖的 Azure 服务之一!

您可以在构建定义中添加一个步骤以将代理 IP 地址列入白名单,然后在构建结束时将其从白名单中删除。 这不是解决方案,而是解决方法,直到 Azure 产品团队将 Azure DevOps 添加为受信任的服务。 感谢@DanielMann 提供这个想法。

解决方案很简单,但我不会相信 ipify.org 作为 REST API 端点来获取我的构建代理的 IP 地址。 相反,我在 Azure Function- GetClientIP 上创建了自己的(并且受信任的)服务。 DevOps 不是我的日常工作,我很难弄清楚如何分配和使用用户定义的变量并将它们传递到管道中的下一步/任务/阶段! 微软关于变量用法的文档对我的帮助还不够,但我在多次不成功的运行后想通了!

在我的博客中查看完整的解决方案 - Azure DevOps Build Pipeline - 使用 Key Vault 中的密钥和机密

我想我会对 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 服务主体已被授予对 Key Vault 机密的读取访问权限
  • 用已知秘密的名称替换knownSecret

奖金:

这使用 Azure CLI 工作,并且已经在 Azure DevOps for Linux 和 Windows 构建代理上进行了测试,后者在 Git bash 下运行。 通常,如果您尝试在 Git Bash 中运行“az”命令,您只会得到“找不到命令”。 我想要一个对两者都适用的解决方案,因为由于 Linux / Windows 构建要求,我需要共享代码。

唯一的解决方案是使用自托管代理

您可以创建一个 VM 并在其中安装代理客户端。 然后您可以在 DevOps 代理池中添加它的新代理并使用它。

由于自代理在 Azure VM 中运行,它肯定会位于虚拟网络中。 通过这种方式,您可以将虚拟网络添加到您的 Key Vault 防火墙白名单。


事实上,我认为你不需要这样做。 因为,没有访问策略,任何人都无法访问您的密钥保管库。 所以,理论上,它是足够安全的。

但是,如果必须使用防火墙和网络规则保护 Key Vault,则可以使用自托管代理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM