web-dev-qa-db-ja.com

VSTSビルドパイプライン:Azure Key Vaultへの接続に失敗するテスト

VSTS(現在のAzure DevOps)を使用してCI/CDパイプラインを実行しようとしています。ビルドパイプラインには、復元、ビルド、テスト、および公開の手順を実行するという非常に基本的なセットアップがあります。

私のテストステップでは、1つのユニットテストプロジェクトと1つの統合テストプロジェクトの2つのテストプロジェクトを実行するようにセットアップしています。自分とAzure Devopsの両方にアクセスできるように、Key Vaultアクセスポリシーを設定しています。 Azure Key Vaultにアクセスできる同じアカウントにログインしているため、Visual Studioを使用してローカルでテストを実行すると、エラーなしでテストを実行できます。

私のアプリケーションは、以下のセットアップを使用してキーボルトにアクセスするように構成されています。

 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>();

ビルドパイプラインを実行するとき、Hosted VS2017インスタンスを使用してプロジェクトをビルドしています。 Key Vaultにアクセスしようとすると失敗する統合テストを除き、すべてが実行されています。次のパッケージを使用しています。

  • Microsoft.Azure.Services.AppAuthentication-Service-to-Azure-Service認証シナリオのアクセストークンを簡単に取得できます。
  • 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 Key Vaultをセットアップし、アプリに統合しました。

ユニットテストと統合テストの両方に合格するようにして、ビルドを機能させようとしています。まだアプリサービスに展開していません。さまざまなサービスをモックしているので、ユニットテストは問題なく実行されます。以下のエラーメッセージで統合テストが失敗します。 Key Vaultへのテストアクセスを取得するにはどうすればよいですか?ホストされたVS2017ビルドのキーボールトに特別なアクセスポリシーを追加する必要がありますか?目立つものが見当たらないので、何をすべきかわからない。

Build

以下は、エラーのスタックトレースです。

    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}が接続文字列で提供されると、ビルドパイプラインが失敗します。ローカルマシンでは動作しますが、ビルドパイプラインでは動作しません。

動作させるには、3つのことをしなければなりませんでした。

  • Azureにログインします。 Azure ADで新しいアプリ登録をセットアップする
  • 新しいADアプリの登録で、新しいクライアントシークレットを作成します enter image description here
  • Key Vaultへの新しいADアプリアクセスを提供します。 Key Vaultアクセスポリシーに移動し、ADで作成したアプリを追加して、シークレットへの読み取りアクセスを許可します。 enter image description here

  • 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アプリのリリースを作成できました。私はこのアプローチには満足していませんが、それは機能しますが、コード自体に秘密の価値を公開するからです。上記のアプローチにより、サービスIDを管理する必要がありません。その点でこれは非常に悪いと思います。

これよりも良い方法がなければなりません。 1つのオプションは、ビルドパイプラインで統合テストを実行しないことです。これが正しいアプローチであるかどうかはわかりません。誰かがこれに対してより良いアプローチを提供できるか、私のアプローチが使用してもいいかどうかを説明できることを望んでいます。

13
Help123

Azure DevOpsの既定のホストエージェントを使用しているため、Azure DevOps Pipelinesビルド内でAzure KeyVaultへの認証の統合テストを実行しないでください。

デフォルトでは、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日更新

より明確にするために、「Update 3」の回避策についても返信します。 MicrosoftがAzure DevOpsのデフォルトのホストされたエージェントを更新したときに回避策がうまく機能するという保証はありません。したがって、さらにポイントを追加する必要があります。データベースサーバーへの接続や(Azure KeyVaultでの)外部認証の使用など、Azure DevOps Pipelinesビルドの領域を超えた他のパーティに依存する統合テストを行うことはお勧めできません特にMicrosoftのデフォルトのホストエージェントを使用している場合は、CI。

無効な認証設定のためにエラーが発生しやすいだけでなく、デフォルトのホストされたエージェントの更なる更新がサードパーティのロジックテストの動作を保証するという保証はありません。

Azure CLIパイプラインタスクを使用して、ソース管理でシークレットを公開せずに、KeyVaultシークレットを必要とする統合テストを実行します。

  1. Azure DevOpsプロジェクトに サービスプリンシパルサービス接続 を作成します。

  2. AzureのVaultにプリンシパルGetおよびList権限を付与します。

  3. Azure CLIタスク内で統合テストを実行します

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

    これが機能するのは、テストがAzure cliのコンテキストで実行されるためです。Azurecliでは、AzureServiceTokenProvider失敗する前からトークンのフェッチを試行します です。 Azure CLIは認証を処理し、タスクが完了するとクリーンアップします。

1
Saeb Amini

自分でまったく同じ問題にぶつかります。 AzureServiceTokenProviderに接続文字列を追加してコードを変更することで、もう少し進めました(渡された既定のパラメーターはnullです)。ただし、Azure DevOpsユーザーがKeyVaultへの必要なアクセス権を持っている場合と持っていない場合があるため、まだ完全には機能しませんでしたが、さらに掘り下げる機会はありませんでした。より良い解決策がここに投稿されることを願っています。

更新 Azure ADにビルドユーザーを追加し、KeyVault内のアクセスポリシーに追加しました。 Get Accessのみを許可する(私たちのテストは、秘密を収集できるかどうかをテストするだけでした)。テストは正常に合格しました。

0
Bobin Cherian