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.
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"
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!
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));
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();
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.
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");
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);
}
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);
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);
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