Implement hashi corp vault
This commit is contained in:
		| @@ -1,93 +1,136 @@ | ||||
| using Azure; | ||||
| using Azure.Security.KeyVault.Secrets; | ||||
| using Azure.Security.KeyVault.Secrets; | ||||
| using VaultSharp; | ||||
| using VaultSharp.V1.AuthMethods.Token; | ||||
| using Core.Blueprint.KeyVault.Configuration; | ||||
| using Microsoft.Extensions.Configuration; | ||||
|  | ||||
| namespace Core.Blueprint.KeyVault | ||||
| namespace Core.Blueprint.KeyVault; | ||||
|  | ||||
| /// <summary> | ||||
| /// Provides operations for managing secrets in Azure Key Vault or HashiCorp Vault transparently based on the environment. | ||||
| /// </summary> | ||||
| public sealed class KeyVaultProvider : IKeyVaultProvider | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Provides operations for managing secrets in Azure Key Vault. | ||||
|     /// </summary> | ||||
|     public sealed class KeyVaultProvider(SecretClient keyVaultProvider): IKeyVaultProvider | ||||
|     private readonly string environment; | ||||
|     private readonly SecretClient? azureClient; | ||||
|     private readonly IVaultClient? hashiClient; | ||||
|     private readonly VaultOptions? hashiOptions; | ||||
|  | ||||
|     public KeyVaultProvider(IConfiguration configuration) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Creates a new secret in Azure Key Vault. | ||||
|         /// </summary> | ||||
|         /// <param name="keyVaultRequest">The request containing the name and value of the secret.</param> | ||||
|         /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|         /// <returns>A <see cref="KeyVaultResponse"/> containing the details of the created secret.</returns> | ||||
|         public async ValueTask<KeyVaultResponse> CreateSecretAsync(KeyVaultRequest keyVaultRequest, CancellationToken cancellationToken) | ||||
|         environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"; | ||||
|  | ||||
|         if (environment == "Local") | ||||
|         { | ||||
|             KeyVaultResponse _response = new(); | ||||
|             KeyVaultSecret azureResponse = await keyVaultProvider.SetSecretAsync(new KeyVaultSecret(keyVaultRequest.Name, keyVaultRequest.Value), cancellationToken); | ||||
|  | ||||
|             _response.Value = azureResponse.Value; | ||||
|             _response.Name = azureResponse.Name; | ||||
|  | ||||
|             return _response; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Deletes a secret from Azure Key Vault if it exists. | ||||
|         /// </summary> | ||||
|         /// <param name="secretName">The name of the secret to delete.</param> | ||||
|         /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|         /// <returns> | ||||
|         /// A <see cref="Tuple"/> containing a status message and a boolean indicating whether the secret was successfully deleted. | ||||
|         /// </returns> | ||||
|         public async ValueTask<Tuple<string, bool>> DeleteSecretAsync(string secretName, CancellationToken cancellationToken) | ||||
|         { | ||||
|             var existingSecret = await this.GetSecretAsync(secretName, cancellationToken); | ||||
|             if (existingSecret != null) | ||||
|             { | ||||
|                 await keyVaultProvider.StartDeleteSecretAsync(secretName, cancellationToken); | ||||
|                 return new("Key Deleted", true); | ||||
|             } | ||||
|  | ||||
|             return new("Key Not Found", false); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Retrieves a secret from Azure Key Vault. | ||||
|         /// </summary> | ||||
|         /// <param name="secretName">The name of the secret to retrieve.</param> | ||||
|         /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|         /// <returns> | ||||
|         /// A <see cref="Tuple"/> containing the <see cref="KeyVaultResponse"/> with secret details  | ||||
|         /// and an optional error message if the secret was not found. | ||||
|         /// </returns> | ||||
|         public async ValueTask<Tuple<KeyVaultResponse, string?>> GetSecretAsync(string secretName, CancellationToken cancellationToken) | ||||
|         { | ||||
|             KeyVaultSecret azureResponse = await keyVaultProvider.GetSecretAsync(secretName, cancellationToken: cancellationToken); | ||||
|  | ||||
|             if (azureResponse == null) | ||||
|             { | ||||
|                 return new(new KeyVaultResponse(), "Key Not Found"); | ||||
|             } | ||||
|  | ||||
|             return new(new KeyVaultResponse { Name = secretName, Value = azureResponse.Value }, string.Empty); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Updates an existing secret in Azure Key Vault. If the secret does not exist, an error is returned. | ||||
|         /// </summary> | ||||
|         /// <param name="newSecret">The updated secret information.</param> | ||||
|         /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|         /// <returns> | ||||
|         /// A <see cref="Tuple"/> containing the updated <see cref="KeyVaultResponse"/> and an optional error message if the secret was not found. | ||||
|         /// </returns> | ||||
|         public async ValueTask<Tuple<KeyVaultResponse, string>> UpdateSecretAsync(KeyVaultRequest newSecret, CancellationToken cancellationToken) | ||||
|         { | ||||
|             KeyVaultResponse _response = new(); | ||||
|             var existingSecret = await this.GetSecretAsync(newSecret.Name, cancellationToken); | ||||
|             if (existingSecret == null) | ||||
|             { | ||||
|                 return new(new KeyVaultResponse(), "Key Not Found"); | ||||
|             } | ||||
|             KeyVaultSecret azureResponse = await keyVaultProvider.SetSecretAsync(new KeyVaultSecret(newSecret.Name, newSecret.Value), cancellationToken); | ||||
|  | ||||
|             _response.Value = azureResponse.Value; | ||||
|             _response.Name = azureResponse.Name; | ||||
|  | ||||
|             return new(new KeyVaultResponse { Name = newSecret.Name, Value = azureResponse.Value }, string.Empty); | ||||
|             hashiOptions = configuration.GetSection("Vault").Get<VaultOptions>(); | ||||
|             hashiClient = new VaultClient(new VaultClientSettings( | ||||
|                 hashiOptions?.Address, | ||||
|                 new TokenAuthMethodInfo(hashiOptions?.Token) | ||||
|             )); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Creates a new secret in Azure Key Vault or HashiCorp Vault. | ||||
|     /// </summary> | ||||
|     /// <param name="keyVaultRequest">The request containing the name and value of the secret.</param> | ||||
|     /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|     /// <returns>A <see cref="KeyVaultResponse"/> containing the details of the created secret.</returns> | ||||
|     public async ValueTask<KeyVaultResponse> CreateSecretAsync(KeyVaultRequest keyVaultRequest, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (environment == "Local") | ||||
|         { | ||||
|             await hashiClient!.V1.Secrets.KeyValue.V2.WriteSecretAsync( | ||||
|                 path: hashiOptions!.SecretPath, | ||||
|                 data: new Dictionary<string, object> { { keyVaultRequest.Name, keyVaultRequest.Value } }, | ||||
|                 mountPoint: hashiOptions.SecretMount | ||||
|             ); | ||||
|             return new KeyVaultResponse { Name = keyVaultRequest.Name, Value = keyVaultRequest.Value }; | ||||
|         } | ||||
|  | ||||
|         KeyVaultSecret azureResponse = await azureClient!.SetSecretAsync( | ||||
|             new KeyVaultSecret(keyVaultRequest.Name, keyVaultRequest.Value), cancellationToken | ||||
|         ); | ||||
|  | ||||
|         return new KeyVaultResponse { Name = azureResponse.Name, Value = azureResponse.Value }; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Deletes a secret from Azure Key Vault or HashiCorp Vault if it exists. | ||||
|     /// </summary> | ||||
|     /// <param name="secretName">The name of the secret to delete.</param> | ||||
|     /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|     /// <returns> | ||||
|     /// A <see cref="Tuple"/> containing a status message and a boolean indicating whether the secret was successfully deleted. | ||||
|     /// </returns> | ||||
|     public async ValueTask<Tuple<string, bool>> DeleteSecretAsync(string secretName, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (environment == "Local") | ||||
|         { | ||||
|             await hashiClient!.V1.Secrets.KeyValue.V2.DeleteSecretAsync( | ||||
|                 path: hashiOptions!.SecretPath, | ||||
|                 mountPoint: hashiOptions.SecretMount | ||||
|             ); | ||||
|  | ||||
|             return new("Key Deleted", true); | ||||
|         } | ||||
|  | ||||
|         var existingSecret = await this.GetSecretAsync(secretName, cancellationToken); | ||||
|         if (existingSecret != null) | ||||
|         { | ||||
|             await azureClient!.StartDeleteSecretAsync(secretName, cancellationToken); | ||||
|             return new("Key Deleted", true); | ||||
|         } | ||||
|  | ||||
|         return new("Key Not Found", false); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Retrieves a secret from Azure Key Vault or HashiCorp Vault. | ||||
|     /// </summary> | ||||
|     /// <param name="secretName">The name of the secret to retrieve.</param> | ||||
|     /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|     /// <returns> | ||||
|     /// A <see cref="Tuple"/> containing the <see cref="KeyVaultResponse"/> with secret details  | ||||
|     /// and an optional error message if the secret was not found. | ||||
|     /// </returns> | ||||
|     public async ValueTask<Tuple<KeyVaultResponse, string?>> GetSecretAsync(string secretName, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (environment == "Local") | ||||
|         { | ||||
|             var secret = await hashiClient!.V1.Secrets.KeyValue.V2.ReadSecretAsync( | ||||
|                 path: hashiOptions!.SecretPath, | ||||
|                 mountPoint: hashiOptions.SecretMount | ||||
|             ); | ||||
|  | ||||
|             if (secret.Data.Data.TryGetValue(secretName, out var value)) | ||||
|             { | ||||
|                 return new(new KeyVaultResponse { Name = secretName, Value = value?.ToString() ?? "" }, string.Empty); | ||||
|             } | ||||
|  | ||||
|             return new(new KeyVaultResponse(), "Key Not Found"); | ||||
|         } | ||||
|  | ||||
|         KeyVaultSecret azureResponse = await azureClient!.GetSecretAsync(secretName, cancellationToken: cancellationToken); | ||||
|         return new(new KeyVaultResponse { Name = secretName, Value = azureResponse.Value }, string.Empty); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Updates an existing secret in Azure Key Vault or HashiCorp Vault. If the secret does not exist, an error is returned. | ||||
|     /// </summary> | ||||
|     /// <param name="newSecret">The updated secret information.</param> | ||||
|     /// <param name="cancellationToken">The cancellation token to cancel the operation.</param> | ||||
|     /// <returns> | ||||
|     /// A <see cref="Tuple"/> containing the updated <see cref="KeyVaultResponse"/> and an optional error message if the secret was not found. | ||||
|     /// </returns> | ||||
|     public async ValueTask<Tuple<KeyVaultResponse, string>> UpdateSecretAsync(KeyVaultRequest newSecret, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var existingSecret = await this.GetSecretAsync(newSecret.Name, cancellationToken); | ||||
|         if (existingSecret == null) | ||||
|         { | ||||
|             return new(new KeyVaultResponse(), "Key Not Found"); | ||||
|         } | ||||
|  | ||||
|         return new(await CreateSecretAsync(newSecret, cancellationToken), string.Empty); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sergio Matias Urquin
					Sergio Matias Urquin