DEV Community

Cover image for Exploring HashiCorp Vault with Vault .NET Client Library
Bervianto Leo Pratama
Bervianto Leo Pratama

Posted on • Edited on

Exploring HashiCorp Vault with Vault .NET Client Library

Hello, everyone! How are you today? I hope you are doing fine. I'm so excited because this is my first post about HashiCorp Vault. In short, Vault is a secret manager, but it's not only that! Please check here for more information about Vault.

This page inspires me to create this post. If you have some questions, feel free to ask me. I expect you already understand Docker and .NET. If you are still unsure, feel free to comment.

Prerequisites

  1. .NET 8 SDK
  2. Docker

Preparing the Project

  1. We will use the project generator provided by .NET 8 SDK. Please generate the solution file. dotnet new sln -o VaultExample.
  2. Change the directory to VaultExample. cd VaultExample.
  3. Now, we will create the Minimal Web API. dotnet new api -o VaultExampleAPI
  4. Add the HashiCrop.Vault to the VaultExampleAPI project. dotnet add VaultExampleAPI package Hashicorp.Vault --version "0.1.0-beta"
  5. Add the VaultExampleAPI to the solution. dotnet sln add VaultExampleAPI.
  6. Now, it's ready to code!

Writing the Code to Read and Write Secrets into Vault

  1. Create VaultData.cs inside VaultExampleAPI directory.

    namespace VaultExampleAPI
    {
        public class VaultData
        {
            public string Name { get; set; }
            public Dictionary<string, string> Data { get; set; }
        }
    }
    
  2. Update Program.cs.

    using Microsoft.AspNetCore.Mvc;
    using System.Text.Json;
    using Vault;
    using Vault.Client;
    using Vault.Model;
    using VaultExampleAPI;
    
    var builder = WebApplication.CreateSlimBuilder(args);
    builder.Logging.AddConsole();
    
    builder.Services.AddSingleton((serviceProvider) =>
    {
       string address = "http://127.0.0.1:8200";
       VaultConfiguration config = new(address);
    
       VaultClient vaultClient = new(config);
       vaultClient.SetToken("dev-only-token");
       return vaultClient;
    });
    
    var app = builder.Build();
    
    var sampleTodos = TodoGenerator.GenerateTodos().ToArray();
    
    var todosApi = app.MapGroup("/todos");
    todosApi.MapGet("/", () => sampleTodos);
    todosApi.MapGet("/{id}", (int id) =>
         sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
             ? Results.Ok(todo)
             : Results.NotFound());
    
     var secretsApi = app.MapGroup("/secrets");
    
     secretsApi.MapPost("/", (VaultClient vaultClient, [FromBody] VaultData secretData) =>
     {
         // Write a secret
         var kvRequestData = new KVv2WriteRequest(secretData.Data);
         vaultClient.Secrets.KVv2Write(secretData.Name, kvRequestData);
         return Results.Ok();
     });
    
     secretsApi.MapGet("/{secretKey}", (ILoggerFactory loggerFactory, VaultClient vaultClient, string secretKey) =>
     {
         var logger = loggerFactory.CreateLogger("vault");
         try
         {
             VaultResponse<object> resp = vaultClient.Secrets.KVv2Read(secretKey);
             var data = resp.Data.ToString();
             return !string.IsNullOrEmpty(data) ? Results.Ok(JsonSerializer.Deserialize<object>(data)) : Results.NotFound();
         }
         catch (VaultApiException ex)
         {
             logger.LogError(ex, "vault error");
             return Results.NotFound();
         }
     });
    
     app.Run();
    

Break Down Each Added Code

  • Let's break down each added code. First, we add the Dependency Injection (DI) for Vault Client as a Singleton. So, we can get the Vault Client in our Minimal Web API through DI.

    builder.Services.AddSingleton((serviceProvider) =>
    {
       string address = "http://127.0.0.1:8200";
       VaultConfiguration config = new(address);
    
       VaultClient vaultClient = new(config);
       vaultClient.SetToken("dev-only-token");
       return vaultClient;
    });
    
  • We create an API group. var secretsApi = app.MapGroup("/secrets");

  • We will use the POST method for writing a secret.

    secretsApi.MapPost("/", (VaultClient vaultClient, [FromBody] VaultData secretData) =>
     {
         // Write a secret
         var kvRequestData = new KVv2WriteRequest(secretData.Data);
         vaultClient.Secrets.KVv2Write(secretData.Name, kvRequestData);
         return Results.Ok();
     });
    
  • We will use the GET {secretKey} for reading the secret.

     secretsApi.MapGet("/{secretKey}", (ILoggerFactory loggerFactory, VaultClient vaultClient, string secretKey) =>
     {
         var logger = loggerFactory.CreateLogger("vault");
         try
         {
             VaultResponse<object> resp = vaultClient.Secrets.KVv2Read(secretKey);
             var data = resp.Data.ToString();
             return !string.IsNullOrEmpty(data) ? Results.Ok(JsonSerializer.Deserialize<object>(data)) : Results.NotFound();
         }
         catch (VaultApiException ex)
         {
             logger.LogError(ex, "vault error");
             return Results.NotFound();
         }
     });
    

More Information About The Codes

You can the repository here. My Pull Request:

Testing our API

  1. Run the Vault server. We can use docker-compose.yml to help us and run docker compose up -d.

    version: '3.9'
    services:
      vault:
        ports:
        - 8200:8200
        environment:
        - VAULT_DEV_ROOT_TOKEN_ID=dev-only-token
        image: vault
    
  2. Open a browser and type localhost:8200. Ensure the Vault page is shown.

    localhost

  3. Run the API. dotnet run VaultExampleAPI

  4. Test use HTTP Client or Postman.

Testing Write Secret

writing secret

Testing Read Secret

Read secret

Read the secret from the Browser

  1. Continue to open localhost:8200 in the browser and input the token dev-only-token.

  2. Click on secret.

    secret

  3. Click on the created secret.

    created secret

  4. You can check the entry.

    entry

Thank you for reading

Thank you for reading. :) Feel free to give feedback in the comment section.

Awesome GIF

Top comments (1)

Collapse
 
coderollercoaster profile image
Felix Turner

This tutorial is a valuable resource for developers interested in learning how to integrate HashiCorp Vault into their .NET applications using the Vault .NET Client Library. The clear explanations and practical examples make it a helpful guide for both beginners and experienced developers looking to enhance their understanding of secret management and secure data storage.