Skip to main content
Version: v1.3.0

Create a new secret provider

Prerequisites

The secret providers are configured during the initial application build-up in the Program.cs:

using Microsoft.Extensions.Hosting;

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureSecretStore((context, config, builder) =>
{
builder.AddEnvironmentVariables();
})
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}

This section describes how a new secret store source can be added to the pipeline.

Developing a secret provider

  1. Install the NuGet package Arcus.Security.Core.

  2. Implement your own implementation of the ISecretProvider ex:

    using Arcus.Security.Core;

    namespace Application.Security.CustomProviders
    {
    public class RegistrySecretProvider : ISecretProvider
    {
    public Task<string> GetRawSecretAsync(string secretName)
    {
    object value = Registry.LocalMachine.GetValue(secretName);
    return Task.FromResult(value?.ToString());
    }

    public async Task<Secret> GetSecretAsync(string secretName)
    {
    string secretValue = await GetRawSecretAsync(secretName);
    return new Secret(secretValue);
    }
    }
    }
  3. Optionally, you can provide an extension for a consumer-friendly way to add the provider. ex:

     namespace Microsoft.Extensions.Hosting
    {
    public static class SecretStoreBuilderExtensions
    {
    public static SecretStoreBuilder AddRegistry(this SecretStoreBuilder builder)
    {
    var provider = new RegistrySecretProvider();
    return builder.AddProvider(provider);
    }
    }
    }

    And in the Startup.cs:

    .ConfigureSecretStore((context, config, builder) =>
    {
    builder.AddRegistry();
    })

    Or, you can use your provider directly.

    .ConfigureSecretStore((context, config, builder) => 
    {
    var provider = new RegistrySecretProvider();
    builder.AddProvider(provider);
    })
  4. Now, the secret source is available in the resulting ISecretProvider registered in the dependency injection container. ex:

    using Arcus.Security.Core;

    namespace Application.Controllers
    {
    [ApiController]
    public class OrderController : ControllerBase
    {
    public class OrderController(ISecretProvider secretProvider)
    {
    }
    }
    }
  5. Note that when your secret provider requires caching, you can wrap the provider in a CachedSecretProvider at registration: ex:

     using Arcus.Security.Core.Caching;

    namespace Microsoft.Extensions.Hosting
    {
    public static class SecretStoreBuilderExtensions
    {
    public static SecretStoreBuilder AddCachedRegistry(this SecretStoreBuilder builder)
    {
    var provider = new RegistrySecretProvider();
    var configuration = new CacheConfiguration(TimeSpan.FromSeconds(5));

    return builder.AddProvider(new CachedSecretProvider(provider, configuration));
    }
    }
    }

    When accessing the provider in the application, you can use the ICachedSecretProvider to have access to the cache-specific methods. ex:

    using Arcus.Security.Core.Caching;

    namespace Application.Controllers
    {
    [ApiController]
    public class OrderController : ControllerBase
    {
    public class OrderController(ICachedSecretProvider secretProvider)
    {
    }
    }
    }

Contribute your secret provider

We are open for contributions and are more than happy to receive pull requests with new secret providers!