Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
dotnet pack ./Commands/Abstractions/Odin.Commands.Abstractions.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./Commands/Core/Odin.Commands.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./Configuration/AzureBlobJson/Odin.Configuration.AzureBlobJson.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./Configuration/PrefixedAzureKeyVaultSecretManager/Odin.Configuration.PrefixedAzureKeyVaultSecretManager.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./Configuration/AzureKeyVault/Odin.Configuration.AzureKeyVault.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./Database/SqlScriptsRunner/Odin.Database.SqlScriptsRunner.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./DesignContracts/Core/Odin.DesignContracts.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
dotnet pack ./DomainDrivenDesign/Core/Odin.DDD.csproj --configuration $CONFIGURATION --output $PACKAGE_DIR
Expand Down
130 changes: 130 additions & 0 deletions Configuration/AzureKeyVault/ConfigurationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using Azure.Core;
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;
using Odin.Configuration;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.Configuration;

public static class ConfigurationBuilderExtensions
{
public const string DefaultAzureKeyVaultConfigurationSectionName = "AzureKeyVault";

/// <summary>
/// Adds Azure Key Vault secrets filtered by a prefix to configuration.
/// </summary>
/// <param name="configBuilder">The configuration builder.</param>
/// <param name="azureKeyVaultConfigurationSectionName">Name of the AzureKeyVault configuration section.
/// The section must contain these string properties:
/// - VaultName or VaultUri
/// - TenantId
/// - ClientId
/// - Secret
/// - Prefix (optional)
/// </param>
/// <param name="options">The optional configuration options for AzureKeyVault load.
/// If passed, the Manager property is set to PrefixedAzureKeyVaultSecretManager.</param>
/// <returns>The configuration builder.</returns>
public static IConfigurationBuilder AddOdinPrefixedAzureKeyVault(this IConfigurationBuilder configBuilder,
string azureKeyVaultConfigurationSectionName = DefaultAzureKeyVaultConfigurationSectionName,
AzureKeyVaultConfigurationOptions? options = null)
{
IConfigurationRoot tempConfig = configBuilder.Build();
IConfigurationSection? section = tempConfig.GetSection(azureKeyVaultConfigurationSectionName);
if (section == null!) return configBuilder;
return AddOdinPrefixedAzureKeyVault(configBuilder, section, options);
}

/// <summary>
/// Adds Azure Key Vault secrets filtered by a prefix to configuration.
/// </summary>
/// <param name="configBuilder">The configuration builder.</param>
/// <param name="akvConfigSection">AzureKeyVault configuration section</param>
/// <param name="options">The optional configuration options for AzureKeyVault load.
/// If passed, the Manager property is set to PrefixedAzureKeyVaultSecretManager.</param>
/// <returns>The configuration builder.</returns>
public static IConfigurationBuilder AddOdinPrefixedAzureKeyVault(this IConfigurationBuilder configBuilder,
IConfigurationSection akvConfigSection,
AzureKeyVaultConfigurationOptions? options = null)
{
ArgumentNullException.ThrowIfNull(akvConfigSection);
string? keyVaultName = akvConfigSection["VaultName"]!;
string? keyVaultUri = akvConfigSection["VaultUri"]!;
string? tenantId = akvConfigSection["TenantId"]!;
string? clientId = akvConfigSection["ClientId"]!;
string? secret = akvConfigSection!["Secret"];
string? prefix = akvConfigSection!["Prefix"];

bool nameOrUriExists = !string.IsNullOrWhiteSpace(keyVaultUri) || !string.IsNullOrWhiteSpace(keyVaultName);

// Silently return if all required config is not present.
if (!nameOrUriExists || string.IsNullOrWhiteSpace(tenantId) || string.IsNullOrWhiteSpace(clientId)
|| string.IsNullOrWhiteSpace(secret))
{
return configBuilder;
}

ClientSecretCredential secretCredentials = new ClientSecretCredential(tenantId, clientId, secret);
if (!string.IsNullOrWhiteSpace(keyVaultName))
{
return configBuilder.AddOdinPrefixedAzureKeyVault(keyVaultName, prefix, secretCredentials, options);
}

Uri akvUri = new Uri(keyVaultUri);
return configBuilder.AddOdinPrefixedAzureKeyVault(akvUri, prefix, secretCredentials, options);
}

/// <summary>
/// Adds Azure Key Vault secrets filtered by a prefix to configuration.
/// Skips configuration loading gracefully if configuration values are missing.
/// </summary>
/// <param name="configBuilder">The configuration builder.</param>
/// <param name="azureKeyVaultName">The Azure Key Vault name or URI. i.e. for 'https://MyVault.vault.azure.net',
/// use 'MyVault'</param>
/// <param name="prefix">Optional prefix to filter secrets by.
/// Secrets starting with this prefix will be loaded with the prefix stripped.</param>
/// <param name="credential">The token credential to use for authentication.</param>
/// <param name="options">The optional configuration options for Azure Key Vault load.
/// If passed, the Manager property is set to PrefixedAzureKeyVaultSecretManager.</param>
/// <returns>The configuration builder.</returns>
public static IConfigurationBuilder AddOdinPrefixedAzureKeyVault(this IConfigurationBuilder configBuilder,
string azureKeyVaultName,
string? prefix,
TokenCredential credential,
AzureKeyVaultConfigurationOptions? options = null)
{
// Guard Clauses
ArgumentNullException.ThrowIfNull(configBuilder);
ArgumentNullException.ThrowIfNull(credential);
ArgumentException.ThrowIfNullOrWhiteSpace(azureKeyVaultName);
Uri vaultUri = new Uri($"https://{azureKeyVaultName}.vault.azure.net/");
return AddOdinPrefixedAzureKeyVault(configBuilder, vaultUri, prefix, credential, options);
}

/// <summary>
/// Adds Azure Key Vault secrets filtered by a prefix to configuration.
/// Skips configuration loading gracefully if configuration values are missing.
/// </summary>
/// <param name="configBuilder"></param>
/// <param name="azureKeyVaultUri"></param>
/// <param name="prefix"></param>
/// <param name="credential"></param>
/// <param name="options"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IConfigurationBuilder AddOdinPrefixedAzureKeyVault(this IConfigurationBuilder configBuilder,
Uri azureKeyVaultUri,
string? prefix,
TokenCredential credential,
AzureKeyVaultConfigurationOptions? options = null)
{
ArgumentNullException.ThrowIfNull(configBuilder);
ArgumentNullException.ThrowIfNull(azureKeyVaultUri);
ArgumentNullException.ThrowIfNull(credential);

prefix = string.IsNullOrWhiteSpace(prefix) ? string.Empty : prefix.Trim();
options ??= new AzureKeyVaultConfigurationOptions();
options.Manager = new PrefixedAzureKeyVaultSecretManager(prefix);
return configBuilder.AddAzureKeyVault(azureKeyVaultUri, credential, options);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>


<PackageIcon>icon.png</PackageIcon>
<RootNamespace>Odin.Configuration</RootNamespace>
<!-- Updated Description -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ public class PrefixedAzureKeyVaultSecretManager : KeyVaultSecretManager
private readonly string _prefix;

/// <summary>
/// Use custom prefix to handle shared Key Vaults where secrets are prefixed with e.g. {Project}-{Environment}-
/// Use custom prefix to handle shared Key Vaults where
/// secret names are prefixed with e.g. '{System}-{Environment}-'
/// </summary>
/// <param name="prefix"></param>
public PrefixedAzureKeyVaultSecretManager(string prefix)
/// <param name="namePrefix">Optional secret name prefix</param>
public PrefixedAzureKeyVaultSecretManager(string? namePrefix)
{
_prefix = prefix;
_prefix = string.IsNullOrWhiteSpace(namePrefix) ? string.Empty : namePrefix;
}

/// <summary>
/// Only load secrets that start with the prefix
/// Only load secrets with a Name that starts with the prefix
/// </summary>
/// <param name="secret"></param>
/// <returns></returns>
Expand All @@ -37,7 +38,7 @@ public override bool Load(SecretProperties secret)
public override string GetKey(KeyVaultSecret secret)
{
// Strip prefix and map "-" to ":"
var key = secret.Name.Substring(_prefix.Length);
string key = secret.Name.Substring(_prefix.Length);
return key.Replace("-", ":");
}
}

This file was deleted.

Loading
Loading