/// <summary> /// Unseals the Vault instance. /// </summary> /// <param name="credentials">The Vault credentials.</param> /// <param name="cancellationToken">The optional <see cref="CancellationToken"/>.</param> /// <returns>The tracking <see cref="Task"/>.</returns> /// <exception cref="HttpException">Thrown for Vault communication problems.</exception> public async Task UnsealAsync(VaultCredentials credentials, CancellationToken cancellationToken = default) { Covenant.Requires <ArgumentNullException>(credentials != null); await jsonClient.PutAsync($"/{vaultApiVersion}/sys/unseal", new JObject(new JProperty("reset", true)), cancellationToken : cancellationToken); for (int i = 0; i < credentials.KeyThreshold; i++) { await jsonClient.PutAsync($"/{vaultApiVersion}/sys/unseal", new JObject(new JProperty("key", credentials.UnsealKeys[i])), cancellationToken : cancellationToken); } }
//--------------------------------------------------------------------- // Static members /// <summary> /// Parse Vault credentials from the results from a <b>vault init</b> command. /// </summary> /// <param name="rawCredentials">The output from the command.</param> /// <param name="keyThreshold">The minimum number of keys required to unseal the Vault.</param> /// <returns>The parsed <see cref="VaultCredentials"/>.</returns> public static VaultCredentials FromInit(string rawCredentials, int keyThreshold) { Covenant.Requires <ArgumentNullException>(rawCredentials != null); Covenant.Requires <ArgumentException>(keyThreshold > 0); const string TokenError = "Invalid HashiCorp Vault Root Token"; const string KeyError = "Invalid HashiCorp Vault Uunseal Key"; var credentials = new VaultCredentials(); // Extract the root token. var tokenPrefix = "Initial Root Token:"; var pos = rawCredentials.IndexOf(tokenPrefix); if (pos == -1) { throw new FormatException("Unable to locate the [Initial Root Token: ###] in the Hashcorp Vault credentials."); } pos += tokenPrefix.Length; var posEnd = rawCredentials.IndexOf('\n', pos); if (posEnd == -1) { throw new FormatException(TokenError); } credentials.RootToken = rawCredentials.Substring(pos, posEnd - pos).Trim(); if (string.IsNullOrEmpty(credentials.RootToken)) { throw new FormatException(TokenError); } // Parse the unseal keys. var keys = new List <string>(); for (int i = 0; i < 10; i++) { var keyPrefix = $"Unseal Key {i + 1}:"; pos = rawCredentials.IndexOf(keyPrefix); if (pos == -1) { break; } pos += keyPrefix.Length; posEnd = rawCredentials.IndexOf('\n', pos); if (posEnd == -1) { throw new FormatException(KeyError); } var key = rawCredentials.Substring(pos, posEnd - pos).Trim(); if (string.IsNullOrEmpty(key)) { throw new FormatException(TokenError); } keys.Add(key); } if (keys.Count == 0) { throw new FormatException("No HashiCorp Vault unseal keys were parsed."); } if (keys.Count < keyThreshold) { throw new FormatException($"HashiCorp Vault unseal key count [{keys.Count}] is less than the key threshold [{keyThreshold}]."); } credentials.UnsealKeys = keys; credentials.KeyThreshold = keyThreshold; return(credentials); }