Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to omit Vault Key name in Configuration Data #10

Merged
merged 2 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ private async Task LoadVaultDataAsync(IVaultClient vaultClient)

if (shouldSetValue)
{
this.SetData(data, key);
this.SetData(data, this.ConfigurationSource.Options.OmitVaultKeyName ? string.Empty : key);

this._versionsCache[key] = secretData.SecretData.Metadata.Version;
}
}
Expand Down
10 changes: 9 additions & 1 deletion Source/VaultSharp.Extensions.Configuration/VaultOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ public class VaultOptions
/// <param name="vaultRoleId">Vault Role ID.</param>
/// <param name="reloadOnChange">Reload secrets if changed in Vault.</param>
/// <param name="reloadCheckIntervalSeconds">Interval in seconds to check Vault for any changes.</param>
/// <param name="omitVaultKeyName">Omit Vault Key Name in Configuration Keys.</param>
public VaultOptions(
string vaultAddress,
string? vaultToken,
string? vaultSecret = null,
string? vaultRoleId = null,
bool reloadOnChange = false,
int reloadCheckIntervalSeconds = 300)
int reloadCheckIntervalSeconds = 300,
bool omitVaultKeyName = false)
{
this.VaultAddress = vaultAddress;
this.VaultToken = vaultToken;
this.VaultSecret = vaultSecret;
this.VaultRoleId = vaultRoleId;
this.ReloadOnChange = reloadOnChange;
this.ReloadCheckIntervalSeconds = reloadCheckIntervalSeconds;
this.OmitVaultKeyName = omitVaultKeyName;
}

/// <summary>
Expand Down Expand Up @@ -60,5 +63,10 @@ public VaultOptions(
/// Gets interval in seconds to check Vault for any changes.
/// </summary>
public int ReloadCheckIntervalSeconds { get; }

/// <summary>
/// Gets a value indicating whether the Vault key should be ommited when generation Configuration key names.
/// </summary>
public bool OmitVaultKeyName { get; }
}
}
94 changes: 94 additions & 0 deletions Tests/VaultSharp.Extensions.Configuration.Test/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace VaultSharp.Extensions.Configuration.Test
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestPlatform.TestHost;
using Newtonsoft.Json;
using Serilog;
using Serilog.Core;
using Serilog.Extensions.Logging;
Expand Down Expand Up @@ -58,6 +59,17 @@ private async Task LoadDataAsync(Dictionary<string, KeyValuePair<string,string>>
}
}

private async Task LoadDataAsync(string secretPath, string jsonData)
{
var authMethod = new TokenAuthMethodInfo("root");

var vaultClientSettings = new VaultClientSettings("http://localhost:8200", authMethod);
IVaultClient vaultClient = new VaultClient(vaultClientSettings);

var dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonData);
await vaultClient.V1.Secrets.KeyValue.V2.WriteSecretAsync(secretPath, dictionary).ConfigureAwait(false);
}

[Fact]
public async Task Success_SimpleTest_TokenAuth()
{
Expand Down Expand Up @@ -94,6 +106,35 @@ public async Task Success_SimpleTest_TokenAuth()
}
}

[Fact]
public async Task Success_SimpleTestOmitVaultKey_TokenAuth()
{
string jsonData = @"{""option1"": ""value1"",""subsection"":{""option2"": ""value2""}}";
var container = this.PrepareVaultContainer();
try
{
await container.StartAsync().ConfigureAwait(false);
await this.LoadDataAsync("myservice-config", jsonData).ConfigureAwait(false);

// act
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddVaultConfiguration(
() => new VaultOptions("http://localhost:8200", "root", omitVaultKeyName: true),
"myservice-config",
"secret",
this._logger);
var configurationRoot = builder.Build();

// assert
configurationRoot.GetValue<string>("option1").Should().Be("value1");
configurationRoot.GetSection("subsection").GetValue<string>("option2").Should().Be("value2");
}
finally
{
await container.DisposeAsync().ConfigureAwait(false);
}
}

[Fact]
public async Task Success_WatcherTest_TokenAuth()
{
Expand Down Expand Up @@ -154,5 +195,58 @@ public async Task Success_WatcherTest_TokenAuth()
await container.DisposeAsync().ConfigureAwait(false);
}
}

[Fact]
public async Task Success_WatcherTest_OmitVaultKey_TokenAuth()
{
// arrange
using CancellationTokenSource cts = new CancellationTokenSource();
string jsonData = @"{""option1"": ""value1"",""subsection"":{""option2"": ""value2""}}";

var container = this.PrepareVaultContainer();
try
{
await container.StartAsync().ConfigureAwait(false);
await this.LoadDataAsync("myservice-config", jsonData).ConfigureAwait(false);


// act
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddVaultConfiguration(
() => new VaultOptions("http://localhost:8200", "root", reloadOnChange: true, reloadCheckIntervalSeconds: 10, omitVaultKeyName: true),
"myservice-config",
"secret",
this._logger);
var configurationRoot = builder.Build();
VaultChangeWatcher changeWatcher = new VaultChangeWatcher(configurationRoot, this._logger);
await changeWatcher.StartAsync(cts.Token).ConfigureAwait(false);
var reloadToken = configurationRoot.GetReloadToken();

// assert
configurationRoot.GetValue<string>("option1").Should().Be("value1");
configurationRoot.GetSection("subsection").GetValue<string>("option2").Should().Be("value2");
reloadToken.HasChanged.Should().BeFalse();

// load new data and wait for reload
jsonData =
@"{""option1"": ""value1_new"",""subsection"": {""option2"": ""value2_new""},""subsection3"": {""option3"": ""value3_new""}}";

await this.LoadDataAsync("myservice-config", jsonData).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(true);

reloadToken.HasChanged.Should().BeTrue();
configurationRoot.GetValue<string>("option1").Should().Be("value1_new");
configurationRoot.GetSection("subsection").GetValue<string>("option2").Should().Be("value2_new");
configurationRoot.GetSection("subsection3").GetValue<string>("option3").Should().Be("value3_new");

changeWatcher.Dispose();
}
finally
{
cts.Cancel();
await container.DisposeAsync().ConfigureAwait(false);
}
}

}
}