Skip to content

niralatuladhar/VaultSharp

 
 

Repository files navigation

VaultSharp

A cross-platform .NET Library for HashiCorp's Vault - A Secret Management System.

VaultSharp 0.10.x is in rapid development. And expected to be released by mid-May 2018.

Join the chat at https://gitter.im/rajanadar-VaultSharp/Lobby License

VaultSharp 0.6.4 is now released and available via NuGet. https://www.nuget.org/packages/VaultSharp/

VaultSharp is now cross-platform (.NET Standard 1.4 other than .NET 4.5.x and .NET 4.6.x compliant)

VaultSharp is also strong named starting 0.6.4. So you might have to do a manual NuGet upgrade, as a one time thing.

Table of Contents

What is VaultSharp?

  • VaultSharp is a C# Library that can be used in any .NET application to interact with Hashicorp's Vault Service.
  • The Vault system is a secret management system built as an Http Service by Hashicorp.
  • This library supports all the Vault Service Apis documented here: https://www.vaultproject.io/docs/http/

VaultSharp 0.6.1 completely supports Hashicorp's Vault 0.6.1

What is the deal with the Versioning of VaultSharp? (Y U NO 1.0.0)

  • This library is written for Hashicorp's Vault Service
  • The Vault service is evolving constantly and the Hashicorp team is rapidly working on it.
  • Pretty soon, they should have an 1.0.0 version of the Vault Service from Hashicorp.
  • Because this client library is intended to facilititate the Vault Service operations, this library makes it easier for its consumers to relate to the Vault service it supports.
  • Hence a version of 0.6.1 denotes that this library will completely support the Vault 0.6.1 Service Apis.
  • Tomorrow when Vault Service gets upgraded to 0.6.2, this library will be modified accordingly and versioned as 0.6.2

How do I use VaultSharp? Give me a code example

// instantiate VaultClient with one of the various authentication options available.
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, authenticationInfo);

// use it for operations.
var consulCredentials = await vaultClient.ConsulGenerateDynamicCredentialsAsync(consulRoleName, consulMountPoint);
var consulToken = consulCredentials.Data.Token;

Does VaultSharp support all the Authentication, Secret and Audit Backends?

  • YES
  • All Authentication, Secret and Audit backends are supported by this library.
  • All administrative (seal, unseal, write policy), end-user (generate credentials) and unauthenticated methods (get status, get root CA) are supported by this client.

VaultSharp and 100% Consul Support

  • VaultSharp supports all the secret backends supported by the Vault 0.6.1 Service.
  • This includes 100% support for a Consul Secret backend, which is the recommended secret backend for Vault.
  • Please look at the API usage in the 'Consul' section of 'Secret Backends' below, to see all the Consul related methods in action.

The fundamental READ and WRITE operations on a Vault

  • The generic READ/WRITE Apis of vault allow you to do a variety of operations.
  • A lot or almost all of these operations are supported in a strongly typed manner with dedicated methods for them in this library.
  • However, for some reason, if you want to use the generic READ and WRITE methods of Vault, you can use them as follows:
var path = "cubbyhole/foo/test";

var secretData = new Dictionary<string, object>
{
    {"1", "1"},
    {"2", 2},
    {"3", false},
};

await vaultClient.WriteSecretAsync(path, secretData);

var secret = await vaultClient.ReadSecretAsync(path);
var data = secret.Data; // this is the original dictionary back.

Can I use it in my PowerShell Automation?

  • Absolutely. VaultSharp is a .NET Library.
  • This means, apart from using it in your C#, VB.NET, J#.NET and any .NET application, you can use it in PowerShell automation as well.
  • Load up the DLL in your PowerShell code and execute the methods. PowerShell can totally work with .NET Dlls.

All the methods are async. How do I use them synchronously?

  • The methods are async as the defacto implementation. The recommended usage.
  • However, there are innumerable scenarios where you would continue to want to use it synchronously.
  • For all those cases, there are various options available to you.
  • There is a lot of discussion around the right usage, avoiding deadlocks etc.
  • This library allows you to set the 'continueAsyncTasksOnCapturedContext' option when you initialize the client.
  • It is an optional parameter and defaults to 'false'
  • Setting it to false, allows you to access the .Result property of the task with reduced/zero deadlock issues.
  • There are other ways as well to invoke it synchronously, and I leave it to the users of the library. (Task.Run etc.)
  • But please note that as much as possible, use it in an async manner.
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, authenticationInfo, continueAsyncTasksOnCapturedContext: true);

var consulSecret = vaultClient.ConsulGenerateDynamicCredentialsAsync(consulRole).Result;

Authentication Backends (All of them are supported)

  • VaultSharp supports all the authentication backends supported by the Vault Service 0.4.0
  • Here is a sample to instantiate the vault client with each of the authentication backends.

App Id Authentication Backend

  • Please note that the app-id auth backend has been deprecated by Vault. They recommend us to use the AppRole backend.
  • VaultSharp still lets you use the app-id Apis, for backward compatibility.
  • You can use the strongly typed api's to configure the appid and userid as follows.
// Configure app-id roles and users as follows.
await AdminVaultClient.AppIdAuthenticationConfigureAppId(appId, policy.Name, appId, path);
await AdminVaultClient.AppIdAuthenticationConfigureUserId(userId, appId, authenticationPath: path);

// now, setup the app-id based auth to get the right token.

IAuthenticationInfo appIdAuthenticationInfo = new AppIdAuthenticationInfo(mountPoint, appId, userId);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, appIdAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the app id and user id.

App Role Authentication Backend

// setup the AppRole based auth to get the right token.

IAuthenticationInfo appRoleAuthenticationInfo = new AppRoleAuthenticationInfo(mountPoint, roleId, secretId);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, appRoleAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the app role and secret id.

AWS-EC2 Authentication Backend

// setup the AWS-EC2 based auth to get the right token.

IAuthenticationInfo awsEc2AuthenticationInfo = new AwcEc2AuthenticationInfo(mountPoint, pkcs7, nonce, roleName);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, awsEc2AuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the aws-ec2 role

GitHub Authentication Backend

IAuthenticationInfo gitHubAuthenticationInfo = new GitHubAuthenticationInfo(mountPoint, personalAccessToken);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, gitHubAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the github token.

LDAP Authentication Backend

IAuthenticationInfo ldapAuthenticationInfo = new LDAPAuthenticationInfo(mountPoint, username, password);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, ldapAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the LDAP username and password.

Certificate (TLS) Authentication Backend

var clientCertificate = new X509Certificate2(certificatePath, certificatePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

IAuthenticationInfo certificateAuthenticationInfo = new CertificateAuthenticationInfo(mountPoint, clientCertificate);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, certificateAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the client certificate.

Token Authentication Backend

IAuthenticationInfo tokenAuthenticationInfo = new TokenAuthenticationInfo(mountPoint, vaultToken);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, tokenAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the vault token.

Username and Password Authentication Backend

IAuthenticationInfo usernamePasswordAuthenticationInfo = new UsernamePasswordAuthenticationInfo(mountPoint, username, password);
IVaultClient vaultClient = VaultClientFactory.CreateVaultClient(vaultUriWithPort, usernamePasswordAuthenticationInfo);

// any operations done using the vaultClient will use the vault token/policies mapped to the username/password.

Secret Backends (All of them are supported)

  • VaultSharp supports all the secret backends supported by the Vault Service 0.4.0
  • Here is a sample to instantiate the vault client with each of the secret backends.

AWS Secret Backend

Configuring an AWS Backend
// mount the backend
await vaultClient.MountSecretBackendAsync(new SecretBackend
{
    BackendType = SecretBackendType.AWS
});

// configure root credentials to create/manage roles and generate credentials
await vaultClient.AWSConfigureRootCredentialsAsync(new AWSRootCredentials
{
    AccessKey = "access-key",
    SecretKey = "secret-key",
    Region = "region"
});

// create a named role with the IAM policy
await vaultClient.AWSWriteNamedRoleAsync("myAwsRole", new AWSRoleDefinition
{
    Policy = "iam-policy-contents"
});
Generate AWS Credentials
var awsCredentials = await vaultClient.AWSGenerateDynamicCredentialsAsync("myAwsRole");
var awsAccessKey = awsCredentials.Data.AccessKey;
var awsSecretKey = awsCredentials.Data.SecretKey;

Cassandra Secret Backend

Configuring a Cassandra Backend
// mount the backend
await vaultClient.MountSecretBackendAsync(new SecretBackend
{
    BackendType = SecretBackendType.Cassandra
});

// configure root connection info to create/manage roles and generate credentials
await vaultClient.CassandraConfigureConnectionAsync(new CassandraConnectionInfo
{
    Hosts = "hosts",
    Username = "username",
    Password = "password"
});

// create a named role
await vaultClient.CassandraWriteNamedRoleAsync("myCassandraRole", new CassandraRoleDefinition
{
    CreationCql = "csql"
});
Generate Cassandra Credentials
var cassandraCredentials = await vaultClient.CassandraGenerateDynamicCredentialsAsync("myCassandraRole");
var cassandraUsername = cassandraCredentials.Data.Username;
var cassandraPassword = cassandraCredentials.Data.Password;

Consul Secret Backend

Configuring a Consul Backend
// mount the backend
var consulAddress = "127.0.0.1:8500";
var consulAclMasterToken = "raja";

var backend = new SecretBackend
{
    BackendType = SecretBackendType.Consul,
};

await vaultClient.MountSecretBackendAsync(backend);

// configure access to Consul and create roles
var consulRole = "consulRole";

await vaultClient.ConsulConfigureAccessAsync(new ConsulAccessInfo()
{
    AddressWithPort = consulAddress,
    ManagementToken = consulAclMasterToken
});

// create a named role
await vaultClient.ConsulWriteNamedRoleAsync(consulRole, new ConsulRoleDefinition()
{
    TokenType = ConsulTokenType.management,
});

var readRole = await vaultClient.ConsulReadNamedRoleAsync(consulRole);
Assert.Equal(ConsulTokenType.management, readRole.Data.TokenType);
Generate Consul Credentials
var consulCredentials = await vaultClient.ConsulGenerateDynamicCredentialsAsync(consulRole);
var consulToken = consulCredentials.Data.Token;
Deleting Role and Unmounting the Consul backend
await vaultClient.ConsulDeleteNamedRoleAsync(consulRole);
await vaultClient.UnmountSecretBackendAsync(SecretBackendType.Consul.Type);

Cubbyhole Secret Backend

var path = "cubbyhole/foo1/foo2";
var values = new Dictionary<string, object>
{
    {"foo", "bar"},
    {"foo2", 345 }
};

await vaultClient.CubbyholeWriteSecretAsync(path, values);

var readValues = await vaultClient.CubbyholeReadSecretAsync(path);
var data = readValues.Data; // gives back the dictionary

await vaultClient.CubbyholeDeleteSecretAsync(path);

Generic Secret Backend

var mountpoint = "secret" + Guid.NewGuid();

var path = mountpoint + "/foo1/blah2";
var values = new Dictionary<string, object>
{
    {"foo", "bar"},
    {"foo2", 345 }
};

await
    vaultClient.MountSecretBackendAsync(new SecretBackend()
    {
        BackendType = SecretBackendType.Generic,
        MountPoint = mountpoint
    });

await vaultClient.GenericWriteSecretAsync(path, values);

var readValues = await vaultClient.GenericReadSecretAsync(path);
var data = readValues.Data; // gives back the dictionary

await vaultClient.GenericDeleteSecretAsync(path);

MongoDB Secret Backend

Configuring a MongoDB Backend
// mount the backend
var mountPoint = "mongodb" + Guid.NewGuid();
var backend = new SecretBackend
{
    MountPoint = mountPoint,
    BackendType = SecretBackendType.MongoDB,
};

await vaultClient.MountSecretBackendAsync(backend);

// configure root connection info to create/manage roles and generate credentials

var mongoDbConnectionInfo = new MongoDbConnectionInfo
{
 ConnectionStringUri = "mongodb://root:[email protected]:27017/admin?ssl=false"
};

await vaultClient.MongoDbConfigureConnectionAsync(mongoDbConnectionInfo, mountPoint);

var lease = new CredentialTimeToLiveSettings
{
    TimeToLive = "1m1s",
    MaximumTimeToLive = "2m1s"
};

await vaultClient.MongoDbConfigureCredentialLeaseSettingsAsync(lease);

// create a named role
var roleName = "mongodb-role";

var role = new MongoDbRoleDefinition
{
    Database = "admin",
    Roles = JsonConvert.SerializeObject(new object[] { "readWrite", new { role = "read", db = "bar" } })
};

await vaultClient.MongoDbWriteNamedRoleAsync(roleName, role);

var queriedRole = await vaultClient.MongoDbReadNamedRoleAsync(roleName);
Generate MongoDB Credentials
var generatedCreds = await vaultClient.MongoDbGenerateDynamicCredentialsAsync(roleName, mountPoint);

var username = generatedCreds.Data.Username;
var password = generatedCreds.Data.Password;

MSSQL Secret Backend

Configuring a MSSQL Backend
// mount the backend
var mountPoint = "mssql" + Guid.NewGuid();
var backend = new SecretBackend
{
    MountPoint = mountPoint,
    BackendType = SecretBackendType.MicrosoftSql,
};

await vaultClient.MountSecretBackendAsync(backend);

// configure root connection info to create/manage roles and generate credentials
var microsoftSqlConnectionInfo = new MicrosoftSqlConnectionInfo
{
    ConnectionString = "server=localhost\sqlexpress;port=1433;user id=sa;password=****;database=master;app name=vault",
    MaximumOpenConnections = 5,
    VerifyConnection = true
};

await vaultClient.MicrosoftSqlConfigureConnectionAsync(microsoftSqlConnectionInfo, mountPoint);

var lease = new CredentialTtlSettings()
{
    TimeToLive = "1m1s",
    MaximumTimeToLive = "2m1s"
};

await vaultClient.MicrosoftSqlConfigureCredentialLeaseSettingsAsync(lease, mountPoint);

// create a named role
var roleName = "msssqlrole";

var role = new MicrosoftSqlRoleDefinition
{
    Sql = "CREATE LOGIN '[{{name}}]' WITH PASSWORD = '{{password}}'; USE master; CREATE USER '[{{name}}]' FOR LOGIN '[{{name}}]'; GRANT SELECT ON SCHEMA::dbo TO '[{{name}}]'"
};

await vaultClient.MicrosoftSqlWriteNamedRoleAsync(roleName, role, mountPoint);

var queriedRole = await vaultClient.MicrosoftSqlReadNamedRoleAsync(roleName, mountPoint);
Generate MSSQL Credentials
var msSqlCredentials = await vaultClient.MicrosoftSqlGenerateDynamicCredentialsAsync(roleName, backend.MountPoint);

var msSqlUsername = msSqlCredentials.Data.Username;
var msSqlPassword = msSqlCredentials.Data.Password;

MySql Secret Backend

Configuring a MySql Backend
// mount the backend
var mountPoint = "mysql" + Guid.NewGuid();
var backend = new SecretBackend
{
    MountPoint = mountPoint,
    BackendType = SecretBackendType.MySql,
};

await vaultClient.MountSecretBackendAsync(backend);

// configure root connection info to create/manage roles and generate credentials
await vaultClient.MySqlConfigureConnectionAsync(new MySqlConnectionInfo()
{
    DataSourceName = "root:root@tcp(127.0.0.1:3306)/"
}, mountPoint);

var sql = "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';";

await vaultClient.MySqlConfigureCredentialLeaseSettingsAsync(new CredentialLeaseSettings()
{
    LeaseDuration = "1h",
    MaximumLeaseDuration = "2h"
}, mountPoint);

// create a named role
var mySqlRole = "mysql-readonly-role";

await vaultClient.MySqlWriteNamedRoleAsync(mySqlRole, new MySqlRoleDefinition()
{
    Sql = sql
}, mountPoint);

var readRole = await vaultClient.MySqlReadNamedRoleAsync(mySqlRole, mountPoint);
var roleSql = readRole.Data.Sql;
Generate MySql Credentials
var mySqlCredentials = await vaultClient.MySqlGenerateDynamicCredentialsAsync(mySqlRole, backend.MountPoint);

var mySqlUsername = mySqlCredentials.Data.Username;
var mySqlPassword = mySqlCredentials.Data.Password;

PKI (Certificates) Secret Backend

Configuring a PKI Backend
// mount the backend
var mountpoint = "pki" + Guid.NewGuid();
var backend = new SecretBackend
{
    BackendType = SecretBackendType.PKI,
    MountPoint = mountpoint
};

await vaultClient.MountSecretBackendAsync(backend);

// write expiry
var expiry = "124h";
var commonName = "blah.example.com";

await vaultClient.PKIWriteCRLExpirationAsync(expiry, mountpoint);

var readExpiry = await vaultClient.PKIReadCRLExpirationAsync(mountpoint);
Assert.Equal(expiry, readExpiry.Data.Expiry);

// read certificate in various ways
var nocaCert = await vaultClient.PKIReadCACertificateAsync(CertificateFormat.pem, mountpoint);
Assert.Null(nocaCert.CertificateContent);

// generate root certificate
var rootCertificateWithoutPrivateKey =
    await vaultClient.PKIGenerateRootCACertificateAsync(new RootCertificateRequestOptions
    {
        CommonName = commonName,
        ExportPrivateKey = false
    }, mountpoint);

Assert.Null(rootCertificateWithoutPrivateKey.Data.PrivateKey);

var rootCertificate =
    await vaultClient.PKIGenerateRootCACertificateAsync(new RootCertificateRequestOptions
    {
        CommonName = commonName,
        ExportPrivateKey = true
    }, mountpoint);

Assert.NotNull(rootCertificate.Data.PrivateKey);

// read certificate in various ways
var caCert = await vaultClient.PKIReadCACertificateAsync(CertificateFormat.pem, mountpoint);
Assert.NotNull(caCert.CertificateContent);

var caReadCert = await vaultClient.PKIReadCertificateAsync("ca", mountpoint);
Assert.Equal(caCert.CertificateContent, caReadCert.Data.CertificateContent);

var caSerialNumberReadCert = await vaultClient.PKIReadCertificateAsync(rootCertificate.Data.SerialNumber, mountpoint);
Assert.Equal(caCert.CertificateContent, caSerialNumberReadCert.Data.CertificateContent);

var crlCert = await vaultClient.PKIReadCertificateAsync("crl", mountpoint);
Assert.NotNull(crlCert.Data.CertificateContent);

var crlCert2 = await vaultClient.PKIReadCRLCertificateAsync(CertificateFormat.pem, mountpoint);
Assert.NotNull(crlCert2.CertificateContent);

// write and read certificate endpoints

var crlEndpoint = _vaultUri.AbsoluteUri + "/v1/" + mountpoint + "/crl";
var issuingEndpoint = _vaultUri.AbsoluteUri + "/v1/" + mountpoint + "/ca";

var endpoints = new CertificateEndpointOptions
{
    CRLDistributionPointEndpoints = string.Join(",", new List<string> { crlEndpoint }),
    IssuingCertificateEndpoints = string.Join(",", new List<string> { issuingEndpoint }),
};

await vaultClient.PKIWriteCertificateEndpointsAsync(endpoints, mountpoint);

var readEndpoints = await vaultClient.PKIReadCertificateEndpointsAsync(mountpoint);

Assert.Equal(crlEndpoint, readEndpoints.Data.CRLDistributionPointEndpoints.First());
Assert.Equal(issuingEndpoint, readEndpoints.Data.IssuingCertificateEndpoints.First());

// rotate CRL
var rotate = await vaultClient.PKIRotateCRLAsync(mountpoint);
Assert.True(rotate);

await vaultClient.RevokeSecretAsync(rootCertificateWithoutPrivateKey.LeaseId);
Write/Read PKI Role
// Create new Role
var roleName = Guid.NewGuid().ToString();

var role = new CertificateRoleDefinition
{
    AllowedDomains = "example.com",
    AllowSubdomains = true,
    MaximumTimeToLive = "72h",
};

await vaultClient.PKIWriteNamedRoleAsync(roleName, role, mountpoint);

var readRole = await vaultClient.PKIReadNamedRoleAsync(roleName, mountpoint);
Assert.Equal(role.AllowedDomains, readRole.Data.AllowedDomains);
Generate PKI Credentials
var certificateCredentials =
    await
        vaultClient.PKIGenerateDynamicCredentialsAsync(roleName,
            new CertificateCredentialsRequestOptions
            {
                CommonName = commonName,
                CertificateFormat = CertificateFormat.pem
            }, mountpoint);

var privateKey = certificateCredentials.Data.PrivateKey;

PostgreSql Secret Backend

Configuring a PostgreSql Backend
// mount the backend
var mountPoint = "postgresql" + Guid.NewGuid();
var backend = new SecretBackend
{
    MountPoint = mountPoint,
    BackendType = SecretBackendType.PostgreSql,
};

await vaultClient.MountSecretBackendAsync(backend);

await vaultClient.PostgreSqlConfigureCredentialLeaseSettingsAsync(new CredentialLeaseSettings()
{
    LeaseDuration = "1h",
    MaximumLeaseDuration = "2h"
}, mountPoint);

// configure root connection info to create/manage roles and generate credentials
await vaultClient.PostgreSqlConfigureConnectionAsync(new PostgreSqlConnectionInfo
{
    ConnectionString = "con_string",
    MaximumOpenConnections = 5
}, mountPoint);

var sql = "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";";

// create a named role
var postgreSqlRole = "postgresql-readonly-role";

await vaultClient.PostgreSqlWriteNamedRoleAsync(postgreSqlRole, new PostgreSqlRoleDefinition()
{
    Sql = sql
}, mountPoint);

var readRole = await vaultClient.PostgreSqlReadNamedRoleAsync(postgreSqlRole, mountPoint);
Assert.Equal(sql, readRole.Data.Sql);
Generate PostgreSql Credentials
var postgreSqlCredentials = await vaultClient.PostgreSqlGenerateDynamicCredentialsAsync(postgreSqlRole, backend.MountPoint);

Assert.NotNull(postgreSqlCredentials.LeaseId);
Assert.NotNull(postgreSqlCredentials.Data.Username);
Assert.NotNull(postgreSqlCredentials.Data.Password);

RabbitMQ Secret Backend

Configuring a RabbitMQ Backend
// mount the backend
await vaultClient.QuickMountSecretBackendAsync(SecretBackendType.RabbitMQ);

// configure root connection info to create/manage roles and generate credentials
var connectionInfo = new RabbitMQConnectionInfo
{
    ConnectionUri = "http://localhost:15672",
    Username = "guest",
    Password = "guest",
    VerifyConnection = true
};

await vaultClient.RabbitMQConfigureConnectionAsync(connectionInfo);

var lease = new CredentialTimeToLiveSettings
{
    TimeToLive = "1m1s",
    MaximumTimeToLive = "2m1s"
};

await vaultClient.RabbitMQConfigureCredentialLeaseSettingsAsync(lease);
var queriedLease = await vaultClient.RabbitMQReadCredentialLeaseSettingsAsync();

var roleName = "rabbitmqrole";

var role = new RabbitMQRoleDefinition
{
    VirtualHostPermissions = "{\"/\":{\"write\": \".*\", \"read\": \".*\"}}"
};

await vaultClient.RabbitMQWriteNamedRoleAsync(roleName, role);

var queriedRole = await vaultClient.RabbitMQReadNamedRoleAsync(roleName);
Generate RabbitMQ Credentials
var generatedCreds = await vaultClient.RabbitMQGenerateDynamicCredentialsAsync(roleName);

Assert.NotNull(generatedCreds.Data.Username);
Assert.NotNull(generatedCreds.Data.Password);

SSH Secret Backend

Configuring a SSH Backend
// mount the backend
var sshKeyName = Guid.NewGuid().ToString();
var sshRoleName = Guid.NewGuid().ToString();

var mountPoint = "ssh" + Guid.NewGuid();
var backend = new SecretBackend
{
    BackendType = SecretBackendType.SSH,
    MountPoint = mountPoint,
};

await vaultClient.MountSecretBackendAsync(backend);

// configure key and role
var privateKey = @"-----BEGIN RSA PRIVATE KEY----- key ---";

var ip = "127.0.0.1";
var user = "rajan";

await vaultClient.SSHWriteNamedKeyAsync(sshKeyName, privateKey, mountPoint);
await vaultClient.SSHWriteNamedRoleAsync(sshRoleName, new SSHOTPRoleDefinition
{
    RoleDefaultUser = user,
    CIDRValues = "127.0.0.1/10",
}, mountPoint);

var role = await vaultClient.SSHReadNamedRoleAsync(sshRoleName, mountPoint);
Assert.True(role.Data.KeyTypeToGenerate == SSHKeyType.otp);
Generate SSH Credentials
var credentials = await
    vaultClient.SSHGenerateDynamicCredentialsAsync(sshRoleName, ip,
        sshBackendMountPoint: mountPoint);

Assert.Equal(user, credentials.Data.Username);

Transit Secret Backend

Configuring a Transit Backend
// mount the backend
var backend = new SecretBackend
{
    BackendType = SecretBackendType.Transit,
    MountPoint = "transit" + Guid.NewGuid(),
};

await vaultClient.MountSecretBackendAsync(backend);

// create encryption key
var keyName = "test_key" + Guid.NewGuid();
var context = "context1";

var plainText = "raja";
var encodedPlainText = Convert.ToBase64String(Encoding.UTF8.GetBytes(plainText));

await vaultClient.TransitCreateEncryptionKeyAsync(keyName, true, backend.MountPoint);
var keyInfo = await vaultClient.TransitGetEncryptionKeyInfoAsync(keyName, backend.MountPoint);

Assert.Equal(keyName, keyInfo.Data.Name);
Assert.True(keyInfo.Data.MustUseKeyDerivation);
Assert.False(keyInfo.Data.IsDeletionAllowed);

// configure the key
await vaultClient.TransitConfigureEncryptionKeyAsync(keyName, isDeletionAllowed: true, transitBackendMountPoint: backend.MountPoint);

keyInfo = await vaultClient.TransitGetEncryptionKeyInfoAsync(keyName, backend.MountPoint);
Assert.True(keyInfo.Data.IsDeletionAllowed);
Encrypt/Decrypt text
var cipherText = await vaultClient.TransitEncryptAsync(keyName, encodedPlainText, context, transitBackendMountPoint: backend.MountPoint);

var plainText2 = Encoding.UTF8.GetString(Convert.FromBase64String((await vaultClient.TransitDecryptAsync(keyName, cipherText.Data.CipherText, context, backend.MountPoint)).Data.PlainText));

Assert.Equal(plainText, plainText2);
Other Transit Operations
await vaultClient.TransitRotateEncryptionKeyAsync(keyName, backend.MountPoint);
var cipherText2 = await vaultClient.TransitEncryptAsync(keyName, encodedPlainText, context, transitBackendMountPoint: backend.MountPoint);

Assert.NotEqual(cipherText.Data.CipherText, cipherText2.Data.CipherText);

var cipherText3 = await vaultClient.TransitRewrapWithLatestEncryptionKeyAsync(keyName, cipherText.Data.CipherText, context, backend.MountPoint);

var newKey1 = await vaultClient.TransitCreateDataKeyAsync(keyName, false, context, 128, backend.MountPoint);
Assert.Null(newKey1.Data.PlainTextKey);

newKey1 = await vaultClient.TransitCreateDataKeyAsync(keyName, true, context, 128, backend.MountPoint);
Assert.NotNull(newKey1.Data.PlainTextKey);

await vaultClient.TransitDeleteEncryptionKeyAsync(keyName, backend.MountPoint);

Audit Backends (All of them are supported)

  • VaultSharp supports all the audit backends supported by the Vault Service 0.4.0
  • Here is a sample to instantiate the vault client with each of the audit backends.

File Audit Backend

var audits = (await vaultClient.GetAllEnabledAuditBackendsAsync()).ToList();

// enable new file audit
var newFileAudit = new FileAuditBackend
{
    BackendType = AuditBackendType.File,
    Description = "store logs in a file - test cases",
    Options = new FileAuditBackendOptions
    {
        FilePath = "/var/log/file"
    }
};

await vaultClient.EnableAuditBackendAsync(newFileAudit);

// get audits
var newAudits = (await vaultClient.GetAllEnabledAuditBackendsAsync()).ToList();
Assert.Equal(audits.Count + 1, newAudits.Count);

// hash with audit
var hash = await vaultClient.HashWithAuditBackendAsync(newFileAudit.MountPoint, "testinput");
Assert.NotNull(hash);

// disabled audit
await vaultClient.DisableAuditBackendAsync(newFileAudit.MountPoint);

Syslog Audit Backend

// enable new syslog audit
var newSyslogAudit = new SyslogAuditBackend
{
    BackendType = AuditBackendType.Syslog,
    Description = "syslog audit - test cases",
    Options = new SyslogAuditBackendOptions()
};

await vaultClient.EnableAuditBackendAsync(newSyslogAudit);

// get audits
var newAudits2 = (await vaultClient.GetAllEnabledAuditBackendsAsync()).ToList();
Assert.Equal(1, newAudits2.Count);

// disabled audit
await vaultClient.DisableAuditBackendAsync(newSyslogAudit.MountPoint);

// get audits
var oldAudits2 = (await vaultClient.GetAllEnabledAuditBackendsAsync()).ToList();
Assert.Equal(audits.Count, oldAudits2.Count);

More Administrative & Other operations

  • VaultSharp supports all the operations supported by the Service.
  • These include administrative ones like Inititalize, Unseal, Seal etc.
  • Here are some samples.
await noAuthInfoClient.InitializeAsync(5, 3, null);
await vaultClient.SealAsync();

await vaultClient.UnsealAsync(masterKey); // need to run this in a loop for all master keys
await vaultClient.UnsealQuickAsync(allMasterKeys);  // unseals the Vault in 1 shot.

await vaultClient.GetSealStatusAsync();

// all policy operations

// write a new policy
var newPolicy = new Policy
{
    Name = "gubdu",
    Rules = "path \"sys/*\" {  policy = \"deny\" }"
};

await vaultClient.WritePolicyAsync(newPolicy);

// get new policy
var newPolicyGet = await vaultClient.GetPolicyAsync(newPolicy.Name);
Assert.Equal(newPolicy.Rules, newPolicyGet.Rules);

// write updates to a new policy
newPolicy.Rules = "path \"sys/*\" {  policy = \"read\" }";

await vaultClient.WritePolicyAsync(newPolicy);

// get new policy
newPolicyGet = await vaultClient.GetPolicyAsync(newPolicy.Name);
Assert.Equal(newPolicy.Rules, newPolicyGet.Rules);

// delete policy
await vaultClient.DeletePolicyAsync(newPolicy.Name);

Miscellaneous Features

  • VaultSharp supports some awesome features like quick mount, quick unseal, quick rekey etc.
  • It also supports setting Proxy settings, custom message handlers for the HttpClient.

Quick mount, unseal and rekey methods

// quickly mount a secret backend
await vaultClient.QuickMountSecretBackendAsync(SecretBackendType.AWS);

// quickly mount an auth backend
await vaultClient.QuickEnableAuthenticationBackendAsync(AuthenticationBackendType.GitHub);

// quickly unseal Vault with a single call.
var sealStatus = await UnauthenticatedVaultClient.QuickUnsealAsync(AllMasterKeys);

// quickly rekey Vault with a single call.
var quick = await UnauthenticatedVaultClient.QuickRekeyAsync(AllMasterKeys, rekeyStatus.Nonce);

Setting Proxy Settings, custom Message Handlers etc.

var vaultClient = VaultClientFactory.CreateVaultClient(VaultUriWithPort, new TokenAuthenticationInfo(someToken), postHttpClientInitializeAction:
    httpClient =>
    {
        // set proxy or custom handlers here.
    });

In Conclusion

Happy Coding folks!

About

A .NET Library for HashiCorp's Vault (Secret Management System) - http://rajanadar.github.io/VaultSharp/

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%