/* * Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Extensions.Loading * File: PluginSecretStore.cs * * PluginSecretStore.cs is part of VNLib.Plugins.Extensions.Loading which is * part of the larger VNLib collection of libraries and utilities. * * VNLib.Plugins.Extensions.Loading is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * VNLib.Plugins.Extensions.Loading is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ using System; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; using VNLib.Utils.Memory; using static VNLib.Plugins.Extensions.Loading.PluginSecretConstants; namespace VNLib.Plugins.Extensions.Loading { /// /// A secret store for a plugin that can be used to fetch secrets from plugin configuration /// /// The plugin instance to get secrets from public readonly struct PluginSecretStore(PluginBase plugin) : IEquatable { private readonly PluginBase _plugin = plugin; /// /// Gets the ambient vault client for the current plugin /// if the configuration is loaded, null otherwise /// /// The ambient if loaded, null otherwise /// /// public IHCVaultClient? GetVaultClient() => LoadingExtensions.GetOrCreateSingleton(_plugin, TryGetVaultLoader); private static HCVaultClient? TryGetVaultLoader(PluginBase pbase) { //Get vault config IConfigScope? conf = pbase.TryGetConfig(VAULT_OBJECT_NAME); if (conf is null) { return null; } //try get server address creds from config string serverAddress = conf.GetRequiredProperty(VAULT_URL_KEY, p => p.GetString()!); bool trustCert = conf.TryGetValue(VAULT_TRUST_CERT_KEY, out JsonElement trustCertEl) && trustCertEl.GetBoolean(); int version = 2; //Default to version 2 now string? authToken; //Get authentication method from config if (conf.TryGetValue(VAULT_TOKEN_KEY, out JsonElement tokenEl)) { //Init token authToken = tokenEl.GetString(); } //Try to get the token as an environment variable else if (Environment.GetEnvironmentVariable(VAULT_TOKNE_ENV_NAME) != null) { authToken = Environment.GetEnvironmentVariable(VAULT_TOKNE_ENV_NAME)!; } else { throw new KeyNotFoundException($"Failed to load the vault authentication method from {VAULT_OBJECT_NAME}"); } _ = authToken ?? throw new KeyNotFoundException($"Failed to load the vault authentication method from {VAULT_OBJECT_NAME}"); //Check for vault kv version, otherwise use the default if (conf.TryGetValue(VAULT_KV_VERSION_KEY, out JsonElement kvVersionEl)) { version = kvVersionEl.GetInt32(); } //create vault client, invalid or nulls will raise exceptions here return HCVaultClient.Create(serverAddress, authToken, version, trustCert, MemoryUtil.Shared); } /// public Task TryGetSecretAsync(string secretName, CancellationToken cancellation = default) { IOnDemandSecret secret = GetOnDemandSecret(secretName); return secret.FetchSecretAsync(cancellation); } /// public ISecretResult? TryGetSecret(string secretName) { IOnDemandSecret secret = GetOnDemandSecret(secretName); return secret.FetchSecret(); } /// public IOnDemandSecret GetOnDemandSecret(string secretName) { ArgumentException.ThrowIfNullOrWhiteSpace(secretName); return new OnDemandSecret(_plugin, secretName, GetVaultClient()); } /// public override bool Equals(object? obj) => obj is PluginSecretStore store && Equals(store); /// public static bool operator ==(PluginSecretStore left, PluginSecretStore right) => left.Equals(right); /// public static bool operator !=(PluginSecretStore left, PluginSecretStore right) => !(left == right); /// public bool Equals(PluginSecretStore other) => ReferenceEquals(other._plugin, _plugin); /// public override int GetHashCode() => _plugin.GetHashCode(); } }