web-dev-qa-db-fra.com

VSTS Build Pipeline: le test échoue lors de la connexion à Azure Key Vault

J'essaie d'utiliser VSTS (maintenant Azure DevOps) pour faire un pipeline CI/CD. Pour mon pipeline de build, j'ai une configuration très basique impliquant de faire des étapes de restauration, de build, de test et de publication.

Pour mon étape de test, je l'ai configuré pour exécuter deux projets de test - un projet de test unitaire et un projet de test d'intégration. J'ai ma configuration de stratégie d'accès Key Vault pour fournir un accès à moi-même et à Azure Devops. Lorsque j'exécute mes tests localement à l'aide de Visual Studio, car je suis connecté au même compte qui a accès au coffre de clés Azure, je peux exécuter les tests sans aucune erreur.

Mon application est configurée pour accéder au coffre de clés à l'aide de la configuration ci-dessous:

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

Lorsque j'exécute le pipeline de génération, j'utilise une instance Hosted VS2017 pour créer mon projet. Tout fonctionne, sauf les tests d'intégration qui tentent d'accéder au coffre de clés échouent. J'utilise les packages suivants:

  • Microsoft.Azure.Services.AppAuthentication - facilite la récupération des jetons d'accès pour les scénarios d'authentification Service-to-Azure-Service.
  • Microsoft.Azure.KeyVault - contient des méthodes pour interagir avec Key Vault.
  • Microsoft.Extensions.Configuration.AzureKeyVault - contient
    Extensions IConfiguration pour Azure Key Vault

J'ai suivi ce tutoriel https://docs.Microsoft.com/en-us/Azure/key-vault/tutorial-web-application-keyvault pour configurer le coffre de clés et l'intégrer dans mon application.

J'essaie simplement de faire fonctionner ma build en m'assurant que les tests unitaires et d'intégration réussissent. Je ne le déploie pas encore sur un service d'application. Les tests unitaires se déroulent sans aucun problème car je me moque des différents services. Mon test d'intégration échoue avec les messages d'erreur ci-dessous. Comment puis-je obtenir mon accès de test au coffre de clés? Dois-je ajouter des stratégies d'accès spéciales à mon coffre de clés pour la version VS2017 hébergée? Je ne sais pas quoi faire car je ne vois rien qui se démarque.

Build

Voici la trace de la pile de l'erreur:

    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)

Mise à jour

Je n'ai trouvé qu'un seul message lié à ce problème: https://social.msdn.Microsoft.com/Forums/en-US/0bac778a-283a-4be1-bc75-605e776adac0/managed-service-identity-issue ? forum = windowsazurewebsitespreview . Mais la publication est liée au déploiement d'une application dans un emplacement Azure. J'essaie simplement de créer mon application dans un pipeline de build.

J'essaie toujours de résoudre ce problème et je ne sais pas quelle est la meilleure façon de fournir l'accès requis.


Update 2

Je n'ai toujours pas trouvé de solution à cela. Je ne sais pas comment faire pour que mon pipeline exécute mon test sans problème. J'ai vu que le pipeline de versions vous permet également d'exécuter des tests. Mais ceux-ci semblent prendre des fichiers .dll et mon fichier de dépôt de pipeline de construction n'a que l'application Web (je ne vois aucun fichier de dépôt publié pour les projets de test). Je ne sais pas si c'est même une possibilité.


Mise à jour 3

J'ai réussi à le faire fonctionner en utilisant la dernière option fournie ici: https://docs.Microsoft.com/en-us/Azure/key-vault/service-to-service-authentication#connection-string -support

J'ai essayé les autres façons d'utiliser un certificat mais à chaque fois que {CurrentUser} est fourni dans une chaîne de connexion, le pipeline de build échoue. Cela fonctionne sur ma machine locale mais pas dans le pipeline de build.

Pour le faire fonctionner, j'ai dû faire trois choses:

  • Connectez-vous à Azure. Configurer un nouvel enregistrement d'application dans Azure AD
  • Dans votre nouvelle inscription d'application AD, créez un nouveau secret client enter image description here
  • Fournissez à votre nouvelle application AD l'accès à votre coffre de clés. Accédez à vos stratégies d'accès au coffre-fort et ajoutez l'application que vous avez créée dans votre AD avec un accès en lecture à vos secrets. enter image description here

  • Modification de mon appel à AzureServiceTokenProvier () dans mon Program.cs fichier comme suit:

     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}")
    

Notez que votre secret client doit être formaté correctement. Les enregistrements d'application (préversion) génèrent une clé secrète aléatoire. Parfois, cette clé ne fonctionne pas dans la chaîne de connexion (renvoie une erreur comme formatée incorrectement). Essayez de générer votre propre clé dans la version sans prévisualisation de l'enregistrement de l'application ou générez une nouvelle clé et réessayez.

Après cela, j'ai réussi à exécuter mon test d'intégration dans mon pipeline de génération avec succès et à créer une version pour mon application Web dans Azure. Je ne suis pas satisfait de cette approche car bien qu'elle fonctionne, elle expose une valeur secrète dans le code lui-même. Gère l'identité du service n'a pas besoin d'être activé en raison de l'approche ci-dessus. Je pense que c'est extrêmement mauvais à cet égard.

Il doit y avoir un meilleur moyen que cela. Une option consiste à ne pas exécuter le test d'intégration dans le pipeline de génération. Je ne sais pas si c'est la bonne approche. J'espère toujours que quelqu'un sera en mesure de fournir une meilleure approche à ce sujet ou d'expliquer si mon approche est correcte à utiliser.

13
Help123

Vous ne devez pas effectuer le test d'intégration de l'authentification à Azure KeyVault dans la génération Azure DevOps Pipelines, car vous utilisez des agents hébergés par défaut Azure DevOps.

Par défaut, les pipelines Azure DevOps utilisent des agents hébergés par défaut de base et ces agents hébergés ne sont pas accessibles à partir de votre abonnement Azure. Ce n'est pas surprenant, car ces agents hébergés sont des agents communs pour tous les besoins de construction courants, y compris la compilation/compilation, l'exécution de tests unitaires, l'obtention de couvertures de test, et toutes ces tâches n'ont pas d'autres fonctionnalités supplémentaires telles qu'avoir ActiveDirectory, une base de données et d'autres authentification/demandes réelles à une autre partie, telles que l'authentification à n'importe quel Azure Keyvault. Par conséquent, ces agents par défaut ne sont pas enregistrés dans votre abonnement Azure.

Si vous souhaitez réussir les tests d'intégration pour ces besoins spéciaux, vous devez créer vos propres agents pour la génération et la publication d'Azure DevOps Pipelines. Par conséquent, il n'existe aucun autre moyen de forcer l'agent par défaut Azure DevOps à exécuter vos tests d'authentification KeyVault, autre que la création de vos propres agents et la configuration de votre Azure DevOps pour utiliser vos propres agents.

Pour créer vos propres agents, consultez cette documentation de Microsoft:

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

MISE À JOUR 29 octobre 2018 :

Pour plus de clarté, je réponds également pour votre solution de contournement "Update 3". Il n'y a aucune garantie que votre solution de contournement fonctionnera correctement lorsque Microsoft mettra à jour l'agent hébergé par défaut d'Azure DevOps. Par conséquent, je dois également ajouter plus de points: ce n'est pas une bonne pratique d'avoir un test d'intégration qui s'appuie sur une autre partie au-delà du domaine de votre build Azure DevOps Pipelines, comme la connexion à un serveur de base de données ou l'utilisation d'authentifications externes (même sur Azure KeyVault) dans votre CI, surtout si vous utilisez les agents hébergés par défaut de Microsoft.

Non seulement il sera sujet aux erreurs en raison d'une configuration d'authentification non valide, mais il n'y a aucune garantie que les mises à jour supplémentaires sur les agents hébergés par défaut garantiraient que votre test de logique tiers fonctionnera.

4

Utilisez tâche de pipeline Azure CLI pour exécuter avec succès les tests d'intégration qui nécessitent des secrets KeyVault, sans exposer aucun secret dans le contrôle de code source:

  1. Créez une connexion au service principal du service dans votre projet Azure DevOps.

  2. Donnez au principal les autorisations Get et List au coffre-fort dans Azure.

  3. Exécutez vos tests d'intégration dans une tâche CLI Azure:

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

    Cela fonctionne car les tests s'exécuteront dans le contexte d'Azure cli, qui est l'endroit où AzureServiceTokenProvideressaie de récupérer un jeton avant qu'il n'échoue . Azure CLI gère l'authentification et nettoie lorsque la tâche est terminée.

1
Saeb Amini

Je rencontre moi-même le même problème. Je suis allé un peu plus loin en modifiant le code en ajoutant une chaîne de connexion à AzureServiceTokenProvider (le paramètre par défaut transmis est nul). Je n'ai toujours pas réussi à le faire fonctionner complètement, peut-être puisque l'utilisateur Azure DevOps peut ou non avoir l'accès requis à KeyVault, mais je n'ai pas eu l'occasion de creuser davantage. En espérant qu'il existe une meilleure solution affichée ici.

pdate Nous avons ajouté l'utilisateur Build dans Azure AD, puis l'avons ajouté aux stratégies d'accès dans KeyVault à l'utilisateur. Ne lui accordant que l'accès (notre test testait uniquement s'il pouvait recueillir le secret). Les tests réussissent maintenant.

0
Bobin Cherian