簡體   English   中英

VSTS 構建管道:測試連接到 Azure Key Vault 失敗

[英]VSTS Build Pipeline: Test fails connecting to Azure Key Vault

我正在嘗試使用 VSTS(現在是 Azure DevOps)來執行 CI/CD 管道。 對於我的構建管道,我有一個非常基本的設置,包括執行還原、構建、測試和發布步驟。

對於我的測試步驟,我將它設置為運行兩個測試項目 - 一個單元測試項目和一個集成測試項目。 我設置了 Key Vault 訪問策略以提供對我自己和 Azure Devops 的訪問。 當我使用 Visual Studio 在本地運行我的測試時,因為我登錄到可以訪問 Azure Key Vault 的同一個帳戶,我可以運行測試而不會出現任何錯誤。

我的應用程序配置為使用以下設置訪問密鑰保管庫:

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((ctx, builder) =>
            {
                var keyVaultEndpoint = GetKeyVaultEndpoint();

                if (!string.IsNullOrEmpty(keyVaultEndpoint))
                {
                    var azureServiceTokenProvider = new AzureServiceTokenProvider();
                    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                    builder.AddAzureKeyVault(keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                }
            }
        )
            .UseStartup<Startup>();

當我運行構建管道時,我使用托管 VS2017 實例來構建我的項目。 除了嘗試訪問密鑰保管庫的集成測試失敗之外,一切都在運行。 我正在使用以下軟件包:

  • Microsoft.Azure.Services.AppAuthentication - 可以輕松獲取服務到 Azure 服務身份驗證方案的訪問令牌。
  • Microsoft.Azure.KeyVault - 包含與 Key Vault 交互的方法。
  • Microsoft.Extensions.Configuration.AzureKeyVault - 包含
    Azure Key Vault 的 IConfiguration 擴展

我按照本教程https://docs.microsoft.com/en-us/azure/key-vault/tutorial-web-application-keyvault設置密鑰保管庫並將其集成到我的應用程序中。

我只是想通過確保單元和集成測試都通過來讓我的構建工作。 我還沒有將它部署到應用服務。 單元測試運行沒有任何問題,因為我正在嘲笑各種服務。 我的集成測試失敗並顯示以下錯誤消息。 如何讓我的測試訪問密鑰保管庫? 我是否需要為托管的 VS2017 版本向我的密鑰保管庫添加任何特殊訪問策略? 不知道該怎么做,因為我沒有看到任何突出的東西。

建造

以下是錯誤的堆棧跟蹤:

    2018-10-16T00:37:04.6202055Z Test run for D:\a\1\s\SGIntegrationTests\bin\Release\netcoreapp2.1\SGIntegrationTests.dll(.NETCoreApp,Version=v2.1)
    2018-10-16T00:37:05.3640674Z Microsoft (R) Test Execution Command Line Tool Version 15.8.0
    2018-10-16T00:37:05.3641588Z Copyright (c) Microsoft Corporation.  All rights reserved.
    2018-10-16T00:37:05.3641723Z 
    2018-10-16T00:37:06.8873531Z Starting test execution, please wait...
    2018-10-16T00:37:51.9955035Z [xUnit.net 00:00:40.80]     SGIntegrationTests.HomeControllerShould.IndexContentTypeIsTextHtml [FAIL]
    2018-10-16T00:37:52.0883568Z Failed   SGIntegrationTests.HomeControllerShould.IndexContentTypeIsTextHtml
    2018-10-16T00:37:52.0884088Z Error Message:
    2018-10-16T00:37:52.0884378Z  Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException : Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/63cd8468-5bc3-4c0a-a6f8-1e314d696937. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
    2018-10-16T00:37:52.0884737Z Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/63cd8468-5bc3-4c0a-a6f8-1e314d696937. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. MSI ResponseCode: BadRequest, Response: {"error":"invalid_request","error_description":"Identity not found"}
    2018-10-16T00:37:52.0884899Z Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/63cd8468-5bc3-4c0a-a6f8-1e314d696937. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "C:\Users\VssAdministrator\AppData\Local\.IdentityService\AzureServiceAuth\tokenprovider.json"
    2018-10-16T00:37:52.0885142Z Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/63cd8468-5bc3-4c0a-a6f8-1e314d696937. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. Process took too long to return the token.
    2018-10-16T00:37:52.0885221Z 
    2018-10-16T00:37:52.0885284Z Stack Trace:
    2018-10-16T00:37:52.0885349Z    at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAccessTokenAsyncImpl(String authority, String resource, String scope)
    2018-10-16T00:37:52.0885428Z    at Microsoft.Azure.KeyVault.KeyVaultCredential.PostAuthenticate(HttpResponseMessage response)
    2018-10-16T00:37:52.0885502Z    at Microsoft.Azure.KeyVault.KeyVaultCredential.ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    2018-10-16T00:37:52.0886831Z    at Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretsWithHttpMessagesAsync(String vaultBaseUrl, Nullable`1 maxresults, Dictionary`2 customHeaders, CancellationToken cancellationToken)
    2018-10-16T00:37:52.0886887Z    at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretsAsync(IKeyVaultClient operations, String vaultBaseUrl, Nullable`1 maxresults, CancellationToken cancellationToken)
    2018-10-16T00:37:52.0886935Z    at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync()
    2018-10-16T00:37:52.0887000Z    at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load()
    2018-10-16T00:37:52.0887045Z    at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
    2018-10-16T00:37:52.0887090Z    at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
    2018-10-16T00:37:52.0887269Z    at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
    2018-10-16T00:37:52.0887324Z    at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
    2018-10-16T00:37:52.0887371Z    at Microsoft.AspNetCore.TestHost.TestServer..ctor(IWebHostBuilder builder, IFeatureCollection featureCollection)
    2018-10-16T00:37:52.0887433Z    at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateServer(IWebHostBuilder builder)
    2018-10-16T00:37:52.0887477Z    at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.EnsureServer()
    2018-10-16T00:37:52.0887525Z    at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)

更新

我只找到了 1 個與此問題相關的帖子: https : //social.msdn.microsoft.com/Forums/en-US/0bac778a-283a-4be1-bc75-605e776adac0/managed-service-identity-issue?forum=windowsazurewebsitespreview . 但該帖子與將應用程序部署到 azure 插槽有關。 我只是想在構建管道中構建我的應用程序。

我仍在嘗試解決此問題,但不確定提供所需訪問權限的最佳方法是什么。


更新 2

我仍然沒有找到解決方案。 我不知道如何讓我的管道毫無問題地運行我的測試。 我看到發布管道也可以選擇運行測試。 但是這些似乎需要 .dll 文件,而我的構建管道放置文件只有 Web 應用程序(我沒有看到任何已發布的測試項目放置文件)。 不確定這是否有可能。


更新 3

我設法使用此處提供的最后一個選項使其工作: https : //docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication#connection-string-support

我嘗試了其他使用證書的方法,但只要在連接字符串中提供 {CurrentUser},構建管道就會失敗。 它適用於我的本地機器,但不適用於構建管道。

為了讓它工作,我必須做三件事:

  • 登錄到 Azure。 在 Azure AD 中設置新的應用注冊
  • 在您的新 AD 應用注冊中,創建一個新的客戶端密鑰在此處輸入圖片說明
  • 為您的新 AD 應用程序提供對密鑰保管庫的訪問權限。 進入您的 Key Vault 訪問策略並添加您在 AD 中創建的具有對您的機密的讀取訪問權限的應用程序。 在此處輸入圖片說明

  • 修改了我在Program.cs文件中對AzureServiceTokenProvier() 的調用,如下所示:

     var azureServiceTokenProvider = new AzureServiceTokenProvider("connectionString={your key vault endpoint};RunAs=App;AppId={your app id that you setup in Azure AD};TenantId={your azure subscription};AppKey={your client secret key}")

請注意,您的客戶端密碼必須正確格式化。 應用程序注冊(預覽)會生成一個隨機密鑰。 有時此鍵在連接字符串中不起作用(由於格式不正確而引發錯誤)。 嘗試在應用注冊的非預覽版中生成您自己的密鑰,或者生成一個新密鑰並重試。

之后,我能夠在我的構建管道中成功運行我的集成測試,並在 Azure 中為我的 Web 應用程序創建一個版本。 我對這種方法並不滿意,因為雖然它有效,但它在代碼本身中暴露了一個秘密值。 由於上述方法,不需要開啟管理服務標識。 我覺得這在這方面是非常糟糕的。

必須有比這更好的方法。 一種選擇是不在構建管道中運行集成測試。 不確定這是否是正確的方法。 我仍然希望有人能夠為此提供更好的方法或解釋我的方法是否可以使用。

使用Azure CLI 管道任務成功運行需要 KeyVault 機密的集成測試,而不會在源代碼控制中公開任何機密:

  1. 在 Azure DevOps 項目中創建服務主體服務連接

  2. 授予主體獲取列出Azure 中 Vault 的權限。

  3. 在 Azure CLI 任務中運行集成測試:

     - task: AzureCLI@1 inputs: azureSubscription: 'Your Service Connection Name' scriptLocation: 'inlineScript' inlineScript: 'dotnet test --configuration $(buildConfiguration) --logger trx'

    這是有效的,因為測試將在 azure cli 的上下文中運行,這是AzureServiceTokenProvider 在失敗之前嘗試AzureServiceTokenProvider 獲取令牌的地方 Azure CLI 處理身份驗證並在任務完成后進行清理。

不應在 Azure DevOps Pipelines 構建中對 Azure KeyVault 進行身份驗證的集成測試,因為你使用的是 Azure DevOps 默認托管代理。

默認情況下,Azure DevOps Pipelines 使用基本的默認托管代理,並且無法從 Azure 訂閱訪問這些托管代理。 這些並不奇怪,因為這些托管代理是所有常見構建需求的通用代理,包括構建/編譯、運行單元測試、獲取測試覆蓋率,並且所有這些任務都沒有其他附加功能,例如擁有 ActiveDirectory、數據庫和其他對其他方的實際身份驗證/請求,例如對任何 Azure Keyvault 的身份驗證。 因此,默認情況下這些代理未在您的 Azure 訂閱中注冊。

如果你希望針對這些特殊需求進行成功的集成測試,則必須為 Azure DevOps Pipelines 構建和發布創建自己的代理。 因此,除了創建您自己的代理並配置您的 Azure DevOps 以使用您自己的代理之外,沒有其他方法可以強制 Azure DevOps 默認代理運行您的 KeyVault 身份驗證測試。

要創建您自己的代理,請參閱 Microsoft 提供的此文檔:

https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=vsts#install

2018 年 10 月 29 日更新

為了更清楚,我還回復了您的“更新 3”解決方法。 當 Microsoft 更新 Azure DevOps 的默認托管代理時,無法保證您的解決方法會很好地工作。 因此,我還需要補充一點:集成測試依賴於 Azure DevOps Pipelines 構建領域之外的其他方,例如連接到數據庫服務器或使用外部身份驗證(即使在 Azure KeyVault 上),這不是一個好的做法。您的 CI,尤其是當您使用 Microsoft 的默認托管代理時。

不僅由於無效的身份驗證配置而容易出錯,而且不能保證默認托管代理的進一步更新將保證您的第三方邏輯測試能夠正常工作。

我自己遇到了完全相同的問題。 通過向 AzureServiceTokenProvider 添加連接字符串(傳遞的默認參數為空)修改代碼,我確實得到了進一步的提升。 我仍然沒有讓它完全工作,也許是因為 Azure DevOps 用戶可能有也可能沒有對 KeyVault 的訪問權限,但我沒有機會進一步挖掘。 希望這里有更好的解決方案。

更新我們將 Build 用戶添加到 Azure AD 中,然后將其添加到 KeyVault 中的用戶訪問策略中。 只授予它獲取訪問權限(我們的測試只是測試它是否可以收集秘密)。 現在測試成功通過。

一個更簡單的解決方案是使用 Azure DevOps 變量組

擁有 DevOps 項目讀取權限和貢獻者的人可以創建變量組,將其鏈接到密鑰保管庫並選擇所需的機密。

變量組現在可以鏈接到您的任何管道。

但是,要使其可用於管道中運行的任何代碼,您必須首先使用此方法導出機密。

您需要通過任務(Azure Powershell 或 Bash)完成此操作,但必須通過內聯腳本完成。 您不能在 t ask 文件中的腳本中導出密鑰庫變量。 因此,在第一個任務中導出所有變量,所有后續任務和引用的腳本都可以使用它們。

電源外殼:

Write-Host "##vso[task.setvariable variable=mysecretexported]$(mysecret1)"
Bash
@echo ##vso[task.setvariable variable=mysecretexported]$(mysecret1)"

You can then refer to the secret using the exported variable

Powershell

Write-Host No problem reading "$env:MYSECRETEXPORTED"

批:

@echo No problem reading %mysecretexported%

Bash 的工作原理類似:

#!/bin/bash

echo "No problem reading $MYSECRETEXPORTED"

這在 YAML 中也受支持

好的部分是這些變量將在您的日志中被屏蔽,因此您的秘密將保密。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM