aboutsummaryrefslogtreecommitdiffstats
path: root/code/api/src/Services/VaultService.cs
blob: 14fb3fb5a7dbc7575aeb64968c5344dbb47cc6fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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<VaultService> _logger;
    private int CACHE_TTL { get; set; }

    public VaultService(HttpClient client, IConfiguration configuration, IMemoryCache cache, ILogger<VaultService> logger) {
        var token = configuration.GetValue<string>(AppEnvironmentVariables.VAULT_TOKEN);
        var vaultUrl = configuration.GetValue<string>(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 T Get<T>(string path) {
        var result = _cache.GetOrCreate(AppConstants.VAULT_CACHE_KEY,
            cacheEntry => {
                cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(CACHE_TTL);
                var getSecretResponse = _client.GetFromJsonAsync<GetSecretResponse<T>>("/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<T>(string path) {
        _cache.Remove(AppConstants.VAULT_CACHE_KEY);
        CACHE_TTL = _configuration.GetValue(AppEnvironmentVariables.VAULT_CACHE_TTL, 60 * 60 * 12);
        return Get<T>(path);
    }

    public async Task<RenewTokenResponse> RenewTokenAsync<T>(string token) {
        var response = await _client.PostAsJsonAsync("v1/auth/token/renew",
            new {
                Token = token
            });
        if (response.IsSuccessStatusCode) {
            return await response.Content.ReadFromJsonAsync<RenewTokenResponse>();
        }

        return default;
    }

    public AppConfiguration GetCurrentAppConfiguration() {
#if DEBUG
        var isInFlightMode = true;
        if (isInFlightMode) {
            return new AppConfiguration() {
                EMAIL_FROM_ADDRESS = "heydev@greatoffice.life",
                DB_HOST = "localhost",
                DB_PORT = "5432",
                DB_NAME = "greatoffice_ivar_dev",
                DB_PASSWORD = "ivar123",
                DB_USER = "postgres",
                CANONICAL_FRONTEND_URL = "http://localhost:5173",
                CANONICAL_BACKEND_URL = "http://localhost:5000",
                POSTMARK_TOKEN = "b530c311-45c7-43e5-aa48-f2c992886e51",
                QUARTZ_DB_HOST = "localhost",
                QUARTZ_DB_PORT = "5432",
                QUARTZ_DB_NAME = "greatoffice_quartz_ivar_dev",
                QUARTZ_DB_PASSWORD = "ivar123",
                QUARTZ_DB_USER = "postgres",
                APP_CERT = "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"
            };
        }
#endif

        var path = _configuration.GetValue<string>(AppEnvironmentVariables.MAIN_CONFIG_SHEET);
        var result = Get<AppConfiguration>(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: {DB_HOST}", 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: {DB_PORT}", 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: {DB_USER}", 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: {DB_NAME}", overwrites.DB_NAME);
            result.DB_NAME = overwrites.DB_NAME;
        }

        return result;
    }

    public AppConfiguration RefreshCurrentAppConfiguration() {
        var path = _configuration.GetValue<string>(AppEnvironmentVariables.MAIN_CONFIG_SHEET);
        return Refresh<AppConfiguration>(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<string> Warnings { get; set; }
        public Auth Auth { get; set; }
    }

    public class Auth
    {
        public string ClientToken { get; set; }
        public string Accessor { get; set; }
        public List<string> Policies { get; set; }
        public List<string> 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<T>
    {
        public VaultSecret<T> Data { get; set; }
    }

    public class VaultSecret<T>
    {
        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; }
    }
}