using Microsoft.Extensions.Caching.Memory; namespace IOL.GreatOffice.Api.Services; public class VaultService { private readonly HttpClient _client; private readonly IMemoryCache _cache; private readonly IConfiguration _configuration; private readonly ILogger _logger; private int CACHE_TTL { get; set; } public VaultService(HttpClient client, IConfiguration configuration, IMemoryCache cache, ILogger logger) { var token = configuration.GetValue(AppEnvironmentVariables.VAULT_TOKEN); var vaultUrl = configuration.GetValue(AppEnvironmentVariables.VAULT_URL); CACHE_TTL = configuration.GetValue(AppEnvironmentVariables.VAULT_CACHE_TTL, 60 * 60 * 12); if (token.IsNullOrWhiteSpace()) throw new ApplicationException("VAULT_TOKEN is empty"); if (vaultUrl.IsNullOrWhiteSpace()) throw new ApplicationException("VAULT_URL is empty"); client.DefaultRequestHeaders.Add("X-Vault-Token", token); client.BaseAddress = new Uri(vaultUrl); _client = client; _cache = cache; _configuration = configuration; _logger = logger; } public static object Data { get; set; } public T Get(string path) { var result = _cache.GetOrCreate(AppConstants.VAULT_CACHE_KEY, cacheEntry => { cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(CACHE_TTL); var getSecretResponse = _client.GetFromJsonAsync>("/v1/kv/data/" + path).Result; if (getSecretResponse == null) { return default; } Log.Debug("Setting new Vault cache, " + new { PATH = path, CACHE_TTL, Data = JsonSerializer.Serialize(getSecretResponse.Data.Data) }); return getSecretResponse.Data.Data ?? default; }); return result; } public T Refresh(string path) { _cache.Remove(AppConstants.VAULT_CACHE_KEY); CACHE_TTL = _configuration.GetValue(AppEnvironmentVariables.VAULT_CACHE_TTL, 60 * 60 * 12); return Get(path); } public async Task RenewTokenAsync(string token) { var response = await _client.PostAsJsonAsync("v1/auth/token/renew", new { Token = token }); if (response.IsSuccessStatusCode) { return await response.Content.ReadFromJsonAsync(); } return default; } public AppConfiguration GetCurrentAppConfiguration() { var path = _configuration.GetValue(AppEnvironmentVariables.MAIN_CONFIG_SHEET); var result = Get(path); var overwrites = new { DB_HOST = _configuration.GetValue("OVERWRITE_DB_HOST", string.Empty), DB_PORT = _configuration.GetValue("OVERWRITE_DB_PORT", string.Empty), DB_USER = _configuration.GetValue("OVERWRITE_DB_USER", string.Empty), DB_PASSWORD = _configuration.GetValue("OVERWRITE_DB_PASSWORD", string.Empty), DB_NAME = _configuration.GetValue("OVERWRITE_DB_NAME", string.Empty), }; if (overwrites.DB_HOST.HasValue()) { _logger.LogInformation("OVERWRITE_DB_HOST is specified, using it's value: " + overwrites.DB_HOST); result.DB_HOST = overwrites.DB_HOST; } if (overwrites.DB_PORT.HasValue()) { _logger.LogInformation("OVERWRITE_DB_PORT is specified, using it's value: " + overwrites.DB_PORT); result.DB_PORT = overwrites.DB_PORT; } if (overwrites.DB_USER.HasValue()) { _logger.LogInformation("OVERWRITE_DB_USER is specified, using it's value: " + overwrites.DB_USER); result.DB_USER = overwrites.DB_USER; } if (overwrites.DB_PASSWORD.HasValue()) { _logger.LogInformation("OVERWRITE_DB_PASSWORD is specified, using it's value: " + "(redacted)"); result.DB_PASSWORD = overwrites.DB_PASSWORD; } if (overwrites.DB_NAME.HasValue()) { _logger.LogInformation("OVERWRITE_DB_NAME is specified, using it's value: " + overwrites.DB_NAME); result.DB_NAME = overwrites.DB_NAME; } return result; } public AppConfiguration RefreshCurrentAppConfiguration() { var path = _configuration.GetValue(AppEnvironmentVariables.MAIN_CONFIG_SHEET); return Refresh(path); } public class RenewTokenResponse { public Guid RequestId { get; set; } public string LeaseId { get; set; } public bool Renewable { get; set; } public long LeaseDuration { get; set; } public object Data { get; set; } public object WrapInfo { get; set; } public List Warnings { get; set; } public Auth Auth { get; set; } } public class Auth { public string ClientToken { get; set; } public string Accessor { get; set; } public List Policies { get; set; } public List TokenPolicies { get; set; } public object Metadata { get; set; } public long LeaseDuration { get; set; } public bool Renewable { get; set; } public string EntityId { get; set; } public string TokenType { get; set; } public bool Orphan { get; set; } public object MfaRequirement { get; set; } public long NumUses { get; set; } } public class GetSecretResponse { public VaultSecret Data { get; set; } } public class VaultSecret { public T Data { get; set; } public VaultSecretMetadata Metadata { get; set; } } public class VaultSecretMetadata { public DateTimeOffset CreatedTime { get; set; } public object CustomMetadata { get; set; } public string DeletionTime { get; set; } public bool Destroyed { get; set; } public long Version { get; set; } } }