hashicorp / vault-client-dotnet

HashiCorp Vault client library in C#
Mozilla Public License 2.0
41 stars 3 forks source link

Vault .NET Client Library

Build NuGet

A .NET client library generated from OpenAPI specification file to interact with Hashicorp Vault.

Note: This library is currently marked as BETA. Please try it out and give us feedback! Please do not use it in production.

Note: We take Vault's security and our users' trust very seriously. If you believe you have found a security issue in Vault .NET, please responsibly disclose by contacting us at security@hashicorp.com.

Contents

Installation

Vault is a package available at Hashicorp Nuget. We've provided install commands below.

Using Powershell:

 Install-Package HashiCorp.Vault -Version "0.2.0"

Using Nuget CLI:

 nuget install HashiCorp.Vault -Version "0.2.0"

Note: You can find the latest package version in the Release tab in GitHub.

You can add the package to your .Net project using the following command:

dotnet add package Hashicorp.Vault -version "0.2.0"

Frameworks supported

Examples

Getting Started

Here is a simple copy-pastable example of using the library to write a secret to the kv secrets engine and then read the secret back. This example works with a Vault server started in dev mode with a hardcoded root token (e.g. vault server -dev -dev-root-token-id="my-token");

using Vault;
using Vault.Client;
using Vault.Model;

namespace Example
{
    public class Example
    {
        public static void Main()
        {
            string address = "http://127.0.0.1:8200";
            VaultConfiguration config = new VaultConfiguration(address);

            VaultClient vaultClient = new VaultClient(config);
            vaultClient.SetToken("my-token");

            try
            {
                var secretData = new Dictionary<string, string> { { "mypass", "pass" } };

                // Write a secret
                var kvRequestData = new KvV2WriteRequest(secretData);

                vaultClient.Secrets.KvV2Write("mypath", kvRequestData);

                // Read a secret
                VaultResponse<KvV2ReadResponse> resp = vaultClient.Secrets.KvV2Read("mypath");
                Console.WriteLine(resp.Data.Data);
            }
            catch (VaultApiException e)
            {
                Console.WriteLine("Failed to read secret with message {0}", e.Message);
            }
        }
    }
}

Note: the responses are currently generic objects that need to be marshalled into an appropriate model. Structured responses are coming soon!

Configuring a Vault Client

The VaultClient requires you pass it a VaultConfiguration object.

VaultConfiguration config = new VaultConfiguration("http:127.0.0.1:8200");
VaultClient vaultClient = new VaultClient(config);

You can also add custom configuration including a custom HttpClientHandler. This can be used to intercept requests and add custom logic before the base SendAsync is called by the HttpClient. See HttpClientHandler docs for more details.

// Create a custom HttpClientHandler
HttpClientHandler myClientHandler = new HttpClientHandler();

VaultConfiguration config = new VaultConfiguration("http://127.0.0.1:8200",
                                          myClientHandler);

The VaultClient also allows you to set a custom Timeout for all API calls.

VaultConfiguration config = new VaultConfiguration(basePath: address,
                                        httpClientHandler: httpClientHandler,
                                        timeout: TimeSpan.FromSeconds(15));

Setting Headers

The SetToken method can be used to set the X-Vault-Token header with the given token for subsequent requests.

vaultClient.SetToken("my-token");

The SetNamespace can be used to set the default namespace header.

vaultClient.SetNamespace("n1");
vaultClient.ClearNamespace();

The Vault client also allows for adding custom headers that will be applied to every request.

IDictionary<string, string> myCustomHeaders = new Dictionary<string, string>
{
    { "my-custom-header", "myHeaders"}
};

vaultClient.AddCustomHeaders(myCustomHeaders);
vaultClient.ClearCustomHeaders();

Authenticating with Vault

In the previous example we used an insecure (root token) authentication method. For production applications, it is recommended to use approle or one of the platform-specific authentication methods instead (e.g. kubernetes, AWS, Azure, etc.). The functions to access these authentication methods are automatically generated under vaultClient.Auth. Below is an example of how to authenticate using approle authentication method. Please refer to the approle documentation for more details.

VaultResponse<Object> resp = vaultClient.Auth.AppRoleLogin(
    new AppRoleLoginRequest(roleId: "myRoleId", secretId: "mySecretId"),
    approleMountPath: "my/mount/path");

vaultClient.SetToken(token: resp.ResponseAuth.ClientToken);

The secret identifier is often delivered as a wrapped token. In this case, you should unwrap it first as demonstrated here.

Reading a KV Secret

To call secrets endpoints, simply use the VaultClient.Secrets object, as shown below.

All secrets and auth calls have an optional mount path parameter that can be specified, otherwise we will use a default mount path.

VaultResponse<KvV2ReadResponse> resp = await vaultClient.Secrets.KvV2ReadAsync("path", secretMountPath: "myCustomMountPath");
Console.WriteLine(resp.Data);

All calls have both an async and synchronous implementation. E.g.

VaultResponse<KvV2ReadResponse> respAsync = await vaultClient.Secrets.KvV2ReadAsync("path");
VaultResponse<KvV2ReadResponse> respSync = vaultClient.Secrets.KvV2ReadAsync("path");

Exception Handling

For api level exceptions we provide the VaultApiException that provides the Vault specific errors, status code and original error content.

try
{
    // Example call to Vault
    vaultClient.System.MountsListSecretsEngines();
}
catch (VaultApiException e)
{
    // Status Code
    Console.WriteLine("Status code: {0}", e.StatusCode);

    // Print the individual errors returned by Vault
    e.Errors.ToList().ForEach(x => Console.WriteLine(x));

    // Well formatted exception message
    Console.WriteLine(e.Message);
}

Wrapping and Unwrapping Responses

All functions accept an optional TimeSpan? wrapTTL function parameter. Vault will wrap the response and return a response-wrapping token instead. More documentation on response wrapping can be found here.

// Get a wrapped response from Vault
VaultResponse<Object> wrappedResp = vaultClient.System.MountsListSecretsEngines(wrapTTL: TimeSpan.FromSeconds(100));

// Unwrap the given response object
VaultResponse<Object> unwrappedResp = vaultClient.Unwrap<Object>(wrappedResp.ResponseWrapInfo.Token);

We also provide an async version.

Task<VaultResponse<Object>> unwrappedResp = await vauClient.UnwrapAsync<Object>(wrappedResp.ResponseWrapInfo.Token);

Performing Generic Operations

We provide generic accessors for Read, Write, List and Delete, should you need to access an endpoint that is not available in the library (e.g. a plugin that is not builtin to Vault).

Each generic operation has a synchronous and asynchronous version.

// Generic read from a path with query parameters
var readPath = "/some/path"
IDictionary<string, object> queryParams = new Dictionary<string, object>
{
    {"key", "value"}
};

VaultResponse<Object> resp = await vaultClient.ReadAsync<Object>(myPath, queryParams);

// Generic write to a path
var writePath = "/some/other/path";
IDictionary<string, object>  secretData = new Dictionary<string, object>
    {
        {"1", "1"},
        {"2", 2},
        {"3", false},
    };

await vaultClient.WriteAsync<Object>(writePath, secretData);

Contributing to Vault .Net Library

Local Development

To develop locally with the Vault .Net Library, you can generate the DLL using your preferred tool (e.g. dotnet build) in the src folder.

Then include the generated DLL (under the bin folder) in the C# project, and use the namespaces:

using Vault;
using Vault.Api;
using Vault.Client;
using Vault.Model;

You will also need to include the following dependencies:

Using your preferred method:

Install-Package Newtonsoft.Json
Install-Package Polly

Documentation for API Endpoints