在 Azure Pipelines 中使用 Azure Key Vault 机密进行单元测试

Use Azure Key Vault Secrets for Unit Tests in Azure Pipelines

我在 .NET 5 中有一个解决方案,其中包含 NUnit 中的一些单元测试,需要一些秘密才能正常工作。在 Visual Studio 中使用本地用户机密进行测试工作正常,但现在我想尝试使用 Azure Key Vault 和 运行 管道内的单元测试进行集成。

我添加了任务 AzureKeyVault@2,根据日志,秘密已 下载 很好,但在接下来的步骤中,单元测试失败,因为它没有尝试从 IConfiguration.

访问时找到一些密钥

这是我的azure-pipelines.yml(只有相关部分)。

- job: Init
  displayName: Unit Testing
  variables:
    solutionToBuild: 'Solution.sln'
    unitTestsProject: 'UnitTests\UnitTests.csproj'
    buildConfiguration: 'Release'
  steps:
  - task: DotNetCoreCLI@2
    displayName: 'Restore Packages'
    inputs:
      command: 'restore'
      projects: '$(solutionToBuild)'
      verbosityRestore: minimal
      feedsToUse: 'select'

  - task: DotNetCoreCLI@2
    displayName: 'Build Solution'
    inputs:
      command: 'build'
      projects: '$(solutionToBuild)'
      arguments: '-c $(buildConfiguration)'

  - task: AzureKeyVault@2
    displayName: 'Configure Key Vault'
    inputs:
      azureSubscription: '**-etc-**'
      KeyVaultName: '**key-vault-name**'

  - task: DotNetCoreCLI@2
    displayName: 'Run Unit Tests'
    inputs:
      command: 'test'
      projects: '$(unitTestsProject)'
      arguments: '-c $(buildConfiguration) --collect:"XPlat Code Coverage"'
      publishTestResults: true

我创建了这个目前在管道中失败的基本测试。我正在使用 Host.CreateDefaultBuilder() 方法来初始化所有单元测试。

[Test]
[TestCase("secret-key-1")]
[TestCase("secret-key-1")]
public void TestSecrets(string key)
{
    Assert.NotNull(_config[key]);
    Assert.IsNotEmpty(_config[key]);
}

AzureKeyVault@2 是否为 DotNetCoreCLI@2 任务传递密钥和值,或者我是否需要额外的步骤?。我读到您可以使用空的 appsettings.json 来玩 FileTransform@1 步骤,但我无法让它工作。有没有正确的方法可以做到这一点?

在管道中使用以下 Keyvault 任务来获取您的 Keyvault 中的机密:

- task: AzureKeyVault@2
    displayName: 'Configure Key Vault'
    inputs:
      azureSubscription: '**-etc-**'
      KeyVaultName: '**key-vault-name**'
      SecretsFilter: '*'
      RunAsPreJob: false

现在,在 DotNetCoreCLI@2 任务中,添加环境变量来定义 keyvault 机密,以便您可以在项目中使用这些环境变量:

- task: DotNetCoreCLI@2 
  displayName: ''
  env:
    MySecret: $(key-vault-secret-name)
  inputs:
    command: ''
    projects: 'project-name'

在您的项目中,您可以按如下方式定义密钥库机密:

var mySecret = Environment.GetEnvironmentVariable("MySecret");

参考:Azure DevOps YAML pipeline : Use Azure KeyVault secret as Environment Variable - DEV Community

我终于成功了。我决定去appsettings.json的路线。与文件转换任务。我会自己回答,以防万一其他人觉得这有用。

您需要在您的单元测试项目中有一个 appsettings.json,并添加您在单元测试中需要的所有必需键,但没有值,只有 "",例如

{
  "secret-key-1": "",
  "secret-key-2": "",
  "secret-key-3": "",
}

如果你想在本地测试,你可以使用 Visual Studio 中的本地用户密码选项,并像在你的 appsettings.json 文件中一样添加所有密钥,但使用实际值(你将是无论如何只有一个查看值)

{
  "secret-key-1": "some-secret-value",
  "secret-key-2": "some-secret-value",
  "secret-key-3": "some-secret-value",
}

然后,在您的 SetUp 方法中,您可以按如下方式初始化 IConfiguration class。 (如果您有多个单元测试 classes,您可以轻松地将其转换为静态方法)

[TestFixture]
public class MyUnitTest

   private IConfiguration Config;

   [SetUp]
   public void Setup()
   {
       Config = new ConfigurationBuilder()
                .SetBasePath(AppContext.BaseDirectory)
                .AddJsonFile("appsettings.json", optional: true)
                .AddUserSecrets(Assembly.GetExecutingAssembly())
                .Build();
   }

   [Test]
   [TestCase("secret-key-1")
   [TestCase("secret-key-2")
   public void TestKeys(string key)
   {
      Assert.NotNull(config[key]);
      Assert.IsNotEmpty(config[key]);
   }
}

最后,在 azure-pipelines.yml 中,在 AzureKeyVault@2 之后添加 FileTransform@1 任务。

  - task: AzureKeyVault@2
    displayName: 'Configure Key Vault'
    inputs:
      azureSubscription: '**-etc-**'
      KeyVaultName: '**key-vault-name**'

  - task: FileTransform@1
    displayName: 'Set Unit Tests Settings'
    inputs:
      folderPath: '$(projectsDirectory)'
      fileType: 'json'
      targetFiles: '**/appsettings.json'

  - task: DotNetCoreCLI@2
    displayName: 'Run Unit Tests'
    inputs:
      command: 'test'
      projects: '$(unitTestsProject)'
      arguments: '-c $(buildConfiguration) --collect:"XPlat Code Coverage"'
      publishTestResults: true

就是这样,之后在管道日志中,您会在 FileTransform@1 任务

中看到类似的内容
Applying JSON variable substitution for **/appsettings.json
Applying JSON variable substitution for D:\a\s\UnitTests\appsettings.json
Substituting value on key secret-key-1 with (string) value: ***
Substituting value on key secret-key-2 with (string) value: ***
Substituting value on key secret-key-3 with (string) value: ***