Connecting to vault and using credentials

Viewed 2520

I am trying to setup hashicorp vault and fetch our key value pairs (database credentials) stored in the vault.

I am following below link to connect to vault and fetch credentials from the vault https://github.com/rajanadar/VaultSharp

I can connect and fetch the credentials fine from the vault but my question is how to pass this credentials to my database context. Do I need to store these credentials somewhere, fetch from there and then pass to my DB context or if I need to intialize this class everytime. Below is the sample code for fetching the credentials

public class VaultService : IVaultService 
{   
    public async Task Configure()
    {
       //code to authenticate role and connect vault here 
       
        //Below is the code that actually fetches the credentials. I am just providing relevant code.
        Secret<SecretData> secret = await vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(kvpPath.Value, mountPoint: "kv");
        foreach (var kvp in secret.Data.Data)
        {
            // Console.WriteLine(kvp.Key + " : " + kvp.Value);
        }      
    }   
}   

How can I use the above class to fetch and pass the credentials.

Below is my startup class where my Database context is defined:

public class Startup
{
   public void ConfigureServices(IServiceCollection services)
   {
      services.AddTransient<IDbAdapterService, DbAdapterService>();     
   }
}

Below is my DbAdapterService where I need to use the credentials

public class DbAdapterService : DbAdapterService
{
      private readonly AppSettings _settings;
      public DbAdapterService(IOptions<AppSettings> settings)
      {
           _settings = settings?.Value;
           DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
           //Below is where I need to update the credentials
           builder.ConnectionString = _settings.ConnectionString;           
      }
}
2 Answers

I think You are doing great. here is the piece you need.

 builder.ConnectionString = "server=(local);user id=*******;" +
        "password=*******;initial catalog=AdventureWorks";
    builder["Server"] = ".";
//set up individual key with value

Now change class

public class DbAdapterService : DbAdapterService ,IVaultService 


{

 

    private readonly AppSettings _settings;
          public DbAdapterService(IOptions<AppSettings> settings)
          {
               _settings = settings?.Value;
    
    Secret<SecretData> secret = await vaultClient.V1.Secrets.KeyValue.V2.ReadSecretAsync(kvpPath.Value, mountPoint: "kv");
      string Key="";
            foreach (var kvp in secret.Data.Data)
            {
                // Console.WriteLine(kvp.Key + " : " + kvp.Value);
    Key= kvp.Value;
            }   
    
            builder.ConnectionString = "server=(local);user id=*******;" +
                "password=*******;initial catalog=AdventureWorks";
            builder["Server"] = Key;
            builder["User ID"] = Key;
           
    }
    
    }

You can simplify & make things robust quite a bit by following ASP.NET Core's configuration abstractions.

ASP.NET Core provides you IConfiguration and IConfigurationProvider interfaces, which abstracts away where and how the configuration is sourced.

You can use Andrew Lock's configuration provider for Hashicorp Vault, NetEscapades.Configuration.Vault, which will let the app fetch the configuration & secrets from a Vault server.

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((ctx, builder)=> 
        {
            // build the initial config
            var builtConfig = config.Build();

            builder.AddVaultWithAppRole(
                config["VaultUri"], //The Vault uri with port
                config["RoleId"], // The role_id for the app
                config["SecretId"], // The secret_iId for the app
                config["SecretPath"] // secret paths to load
                );
        })
        .UseStartup<Startup>()
        .Build();

then inside the Startup class, you can use IConfiguration and get the connection string to configure the DbContext.

public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services) {
    services.AddDbContext<AppDbContext>(o => 
        o.UseSqlServer(Configuration.GetConnectionString("SqlServer"))
    );
}

References:

Related