public async Task <IEnumerable <BlobId> > ListAsync(ListOptions options, CancellationToken cancellationToken) { if (options == null) { options = new ListOptions(); } GenericValidation.CheckBlobPrefix(options.Prefix); var secretNames = new List <BlobId>(); IPage <SecretItem> page = await _vaultClient.GetSecretsAsync(_vaultUri); do { secretNames.AddRange(page.Select(ToBlobId)); }while (page.NextPageLink != null && (page = await _vaultClient.GetSecretsNextAsync(page.NextPageLink)) != null); if (options.Prefix == null) { return(secretNames); } return(secretNames .Where(options.IsMatch) .Take(options.MaxResults == null ? int.MaxValue : options.MaxResults.Value)); }
public async Task <IReadOnlyCollection <Blob> > ListAsync(ListOptions options, CancellationToken cancellationToken) { if (options == null) { options = new ListOptions(); } GenericValidation.CheckBlobPrefix(options.FilePrefix); if (!StoragePath.IsRootPath(options.FolderPath)) { return(new List <Blob>()); } var secretNames = new List <Blob>(); IPage <SecretItem> page = await _vaultClient.GetSecretsAsync(_vaultUri).ConfigureAwait(false); do { var ids = page .Select((Func <SecretItem, Blob>)AzureKeyVaultBlobStorageProvider.ToBlobId) .Where(options.IsMatch) .Where(s => options.BrowseFilter == null || options.BrowseFilter(s)) .ToList(); secretNames.AddRange(ids); if (options.MaxResults != null && secretNames.Count >= options.MaxResults.Value) { return(secretNames.Take(options.MaxResults.Value).ToList()); } }while (page.NextPageLink != null && (page = await _vaultClient.GetSecretsNextAsync(page.NextPageLink).ConfigureAwait(false)) != null); return(secretNames); }
private List <string> GetAllKeys() { List <string> keys = new List <string>(); // KeyVault keys are case-insensitive. There won't be case-duplicates. List<> should be fine. // Get first page of secret keys var allSecrets = Task.Run(async() => { return(await _kvClient.GetSecretsAsync(_uri)); }).Result; foreach (var secretItem in allSecrets) { keys.Add(secretItem.Identifier.Name); } // If there more more pages, get those too string nextPage = allSecrets.NextPageLink; while (!String.IsNullOrWhiteSpace(nextPage)) { var moreSecrets = Task.Run(async() => { return(await _kvClient.GetSecretsNextAsync(nextPage)); }).Result; foreach (var secretItem in moreSecrets) { keys.Add(secretItem.Identifier.Name); } nextPage = moreSecrets.NextPageLink; } return(keys); }
public async Task <int> ExecuteAsync() { Console.WriteLine($"Verifying {VaultOptions.VaultUrl} Key Vault"); var azureServiceTokenProvider = new AzureServiceTokenProvider(); var authCallback = new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback); var keyVaultClient = new KeyVaultClient(authCallback); var result = await keyVaultClient.GetSecretsAsync(VaultOptions.VaultUrl); while (true) { foreach (Microsoft.Azure.KeyVault.Models.SecretItem item in result) { var secret = await keyVaultClient.GetSecretAsync(item.Id); Console.WriteLine($" - {item.Id}"); Console.WriteLine($" {secret.Value}"); } if (result.NextPageLink == null) { break; } result = await keyVaultClient.GetSecretsNextAsync(result.NextPageLink); } return(0); }
/// <summary> /// Lists secrets in a vault /// </summary> private static void ListSecrets() { var vaultAddress = inputValidator.GetVaultAddress(); var numSecretsInVault = 0; var maxResults = 1; Console.Out.WriteLine("List secrets:---------------"); var results = keyVaultClient.GetSecretsAsync(vaultAddress, maxResults).GetAwaiter().GetResult(); if (results != null) { numSecretsInVault += results.Count(); foreach (var m in results) { Console.Out.WriteLine("\t{0}", m.Identifier.Name); } } while (results != null && !string.IsNullOrWhiteSpace(results.NextPageLink)) { results = keyVaultClient.GetSecretsNextAsync(results.NextPageLink).GetAwaiter().GetResult(); if (results != null) { numSecretsInVault += results.Count(); foreach (var m in results) { Console.Out.WriteLine("\t{0}", m.Identifier.Name); } } } Console.Out.WriteLine("\n\tNumber of secrets in the vault: {0}", numSecretsInVault); }
/// <summary> /// Print all secrets in azure key vault. /// </summary> /// <param name="vaultUri">The key vault uri.</param> /// <param name="clientId">The service principal id.</param> /// <param name="clientSecret">The service principal secret.</param> /// <returns>The async task for printing operation.</returns> private static async Task PrintKeyVaultSecretsAsync( string vaultUri, string clientId, string clientSecret) { KeyVaultClient keyVaultClient = CreateKeyVaultClient(clientId, clientSecret); IPage <SecretItem> secretsPage = await keyVaultClient.GetSecretsAsync(vaultUri); do { foreach (SecretItem secret in secretsPage) { string secretName = secret.Identifier.Name; SecretBundle secretBundle = await keyVaultClient.GetSecretAsync( secret.Identifier.Identifier); string secretValue = secretBundle.Value; Console.WriteLine($"{secretName}: {secretValue}"); } if (secretsPage.NextPageLink != null) { secretsPage = await keyVaultClient.GetSecretsNextAsync( secretsPage.NextPageLink); } } while (secretsPage.NextPageLink != null); }
/// <summary> /// Delete a secret from Key Vault /// </summary> /// <param name="keyvaultName">ID of the secret</param> /// <returns>secret value</returns> public async Task <ApiResult> GetAndDeleteSecretsAsync(string keyvaultName, string flowId) { try { var secretUrl = GetKeyVaultSecretUrl(keyvaultName); var secrets = await _keyVaultClient.GetSecretsAsync(secretUrl); foreach (Microsoft.Azure.KeyVault.Models.SecretItem secretItem in secrets) { if (secretItem.Identifier.Name.StartsWith($"{flowId}-")) { await DeleteSecretAsync(keyvaultName, secretItem.Identifier.Name); } } while (!string.IsNullOrWhiteSpace(secrets.NextPageLink)) { secrets = await _keyVaultClient.GetSecretsNextAsync(secrets.NextPageLink); foreach (Microsoft.Azure.KeyVault.Models.SecretItem secretItem in secrets) { if (secretItem.Identifier.Name.StartsWith($"{flowId}-")) { await DeleteSecretAsync(keyvaultName, secretItem.Identifier.Name); } } } return(ApiResult.CreateSuccess("Deleted")); } catch (Exception) { throw; } }
private static async Task <Keyring> GenerateKeyring(KeyVaultClient client, string vault, string prefix) { var secrets = await client.GetSecretsAsync(vault); var allSecrets = new List <SecretItem>(secrets.Value); while (secrets.NextLink != null) { secrets = await client.GetSecretsNextAsync(secrets.NextLink); allSecrets.AddRange(secrets.Value); } var keyring = new Keyring(); foreach (var secret in allSecrets.Where(s => s.Identifier.Name.StartsWith(prefix))) { var secretItem = await client.GetSecretAsync(secret.Id); var bytes = System.Convert.FromBase64String(secretItem.Value); keyring.ImportFromStream(new MemoryStream(bytes)); } return(keyring); }
private async static Task <TResult> GetKeyVaultSecretsAsync <TResult>(string vaultUrl, string clientId, string clientSecret, Func <Dictionary <string, string>, TResult> onFound, Func <TResult> onNotFound, Func <TResult> onKeyVaultTokenInvalid, Func <TResult> onKeyVaultNotConfigured) { if (string.IsNullOrEmpty(vaultUrl) || string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret)) { return(onKeyVaultNotConfigured()); } try { var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback( async(authority, resource, scope) => await GetTokenAsync(clientId, clientSecret, authority, resource, scope))); var secretBundle = await keyVaultClient.GetSecretsAsync(vaultUrl); if (null == secretBundle) { return(onNotFound()); } // The api returns 25 keys at a time var names = secretBundle.Select(secret => secret.Identifier.Name).ToArray(); while (!string.IsNullOrEmpty(secretBundle.NextPageLink)) { secretBundle = await keyVaultClient.GetSecretsNextAsync(secretBundle.NextPageLink); if (secretBundle == null) { break; } names = names.Concat(secretBundle.Select(secret => secret.Identifier.Name)).ToArray(); } ; var secrets = await names .Select( async name => { var secret = await keyVaultClient.GetSecretAsync(vaultUrl, name); var value = (null == secret) ? string.Empty : secret.Value; // KeyVault will only allow Alphanumberic characters and dashes. Replace - with . to keep our // current naming convention. Yes - this means we cannot have dashes in our names. return(name.Replace("-", ".").PairWithValue(value)); }).WhenAllAsync(1); return(onFound(secrets.ToDictionary())); } catch (Exception) { return(onKeyVaultTokenInvalid()); } }
public static async Task <List <IEnumerable <SecretItem> > > GetKeyVaultSecretsPagesAsync(KeyVaultClient keyVaultClient, string keyVaultBaseUrl) { IPage <SecretItem> secretItems = await keyVaultClient.GetSecretsAsync(keyVaultBaseUrl); List <IEnumerable <SecretItem> > secretsPages = new List <IEnumerable <SecretItem> >() { secretItems }; while (!string.IsNullOrEmpty(secretItems.NextPageLink)) { secretItems = await keyVaultClient.GetSecretsNextAsync(secretItems.NextPageLink); secretsPages.Add(secretItems); } return(secretsPages); }
public async Task <IEnumerable <Secret> > Get(String vaultName) { Logger.LogTrace("GetSecrets({0})", vaultName); var client = new KeyVaultClient(this.Authenticate); var results = new List <Secret>(); var secrets = await client.GetSecretsAsync(GetVaultUrl(vaultName)); do { foreach (var s in secrets) { results.Add(new Secret { Id = s.Id, Name = s.Identifier.Name, ContentType = s.ContentType }); } secrets = await client.GetSecretsNextAsync(secrets.NextPageLink); } while (!String.IsNullOrEmpty(secrets.NextPageLink)); return(results); }
public async Task <List <Secret> > GetSecretsAsync(bool cacheSecrets = true) { var secrets = new List <Secret>(); var nextPageLink = string.Empty; do { var page = string.IsNullOrEmpty(nextPageLink) ? await _keyVaultClient.GetSecretsAsync(_vaultUri) : await _keyVaultClient.GetSecretsNextAsync(nextPageLink); foreach (var secret in page) { var model = new Secret(secret.Id, secret.Identifier.Name); secrets.Add(model); if (cacheSecrets) { await _cache.SetAsync(model.Key, model.Value); } } } while (!string.IsNullOrEmpty(nextPageLink)); return(secrets); }
/// <inheritdoc /> public Task <IPage <SecretItem> > GetSecretsNextAsync(string nextLink) { return(_keyVaultClientImplementation.GetSecretsNextAsync(nextLink)); }
private async Task MigrationGuide() { #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_Create AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); KeyVaultClient client = new KeyVaultClient( new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback)); #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_Create #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_CreateWithOptions using (HttpClient httpClient = new HttpClient()) { //@@AzureServiceTokenProvider provider = new AzureServiceTokenProvider(); /*@@*/ provider = new AzureServiceTokenProvider(); //@@KeyVaultClient client = new KeyVaultClient( /*@@*/ client = new KeyVaultClient( new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback), httpClient); } #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_CreateWithOptions { #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_SetSecret SecretBundle secret = await client.SetSecretAsync("https://myvault.vault.azure.net", "secret-name", "secret-value"); #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_SetSecret } { #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_GetSecret // Get the latest secret value. SecretBundle secret = await client.GetSecretAsync("https://myvault.vault.azure.net", "secret-name", null); // Get a specific secret value. SecretBundle secretVersion = await client.GetSecretAsync("https://myvault.vault.azure.net", "secret-name", "e43af03a7cbc47d4a4e9f11540186048"); #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_GetSecret } { #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_ListSecrets IPage <SecretItem> page = await client.GetSecretsAsync("https://myvault.vault.azure.net"); foreach (SecretItem item in page) { SecretIdentifier secretId = item.Identifier; SecretBundle secret = await client.GetSecretAsync(secretId.Vault, secretId.Name); } while (page.NextPageLink != null) { page = await client.GetSecretsNextAsync(page.NextPageLink); foreach (SecretItem item in page) { SecretIdentifier secretId = item.Identifier; SecretBundle secret = await client.GetSecretAsync(secretId.Vault, secretId.Name); } } #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_ListSecrets } { #region Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_DeleteSecret // Delete the secret. DeletedSecretBundle deletedSecret = await client.DeleteSecretAsync("https://myvault.vault.azure.net", "secret-name"); // Purge or recover the deleted secret if soft delete is enabled. if (deletedSecret.RecoveryId != null) { DeletedSecretIdentifier deletedSecretId = deletedSecret.RecoveryIdentifier; // Deleting a secret does not happen immediately. Wait a while and check if the deleted secret exists. while (true) { try { await client.GetDeletedSecretAsync(deletedSecretId.Vault, deletedSecretId.Name); // Finally deleted. break; } catch (KeyVaultErrorException ex) when(ex.Response.StatusCode == HttpStatusCode.NotFound) { // Not yet deleted... } } // Purge the deleted secret. await client.PurgeDeletedSecretAsync(deletedSecretId.Vault, deletedSecretId.Name); // You can also recover the deleted secret using RecoverDeletedSecretAsync. } #endregion Snippet:Microsoft_Azure_KeyVault_Snippets_MigrationGuide_DeleteSecret } }
/// <summary> /// Processes the certificate management. /// </summary> /// <param name="directoryPath">Directory to put the certificatex in.</param> /// <param name="certConfiguration">Certificate configuration. This is a combination of comma separated values in following format /// *certFileName*;*SourceOfCert*;*CertIdentifierInSource*.</param> /// <param name="keyVaultUris">KeyVault uris if key vault is to be used.</param> /// <param name="keyVaultClientId">Application client Id to access keyvault.</param> /// <param name="keyVaultClientSecret">Application client secret to access keyvault.</param> /// <param name="keyVaultClientCert">Application client certificate thumbprint if the keyvault app has certificate credentials.</param> /// <param name="useManagedIdentity">Use managed identity.</param> /// <returns>Exit code for the operation.</returns> internal static async Task <ExitCode> ProcessAsync( string directoryPath, string certConfiguration, List <string> keyVaultUris, string keyVaultClientId, string keyVaultClientSecret, string keyVaultClientCert, bool useManagedIdentity) { if (string.IsNullOrEmpty(directoryPath)) { Logger.LogError(CallInfo.Site(), "Directory path missing for the Certificate directory."); return(ExitCode.DirectoryPathMissing); } if (string.IsNullOrEmpty(certConfiguration)) { Logger.LogError(CallInfo.Site(), "Cert configuration missing. Please specify CertsToConfigure option"); return(ExitCode.InvalidCertConfiguration); } // 1. Initialize KeyVault Client if params were passed. KeyVaultClient keyVaultClient = null; Dictionary <string, string> keyVaultSecretMap = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); if (keyVaultUris.Any()) { KeyVaultClient.AuthenticationCallback callback = null; if (useManagedIdentity) { string connectionString = "RunAs=App"; if (!string.IsNullOrEmpty(keyVaultClientId)) { connectionString = connectionString + ";AppId=" + keyVaultClientId; } AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider(connectionString); callback = new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback); } else { if (string.IsNullOrEmpty(keyVaultClientId)) { Logger.LogError(CallInfo.Site(), "If KeyVaultUri is specified and managed identity is not used, KeyVault ClientId must be specified"); return(ExitCode.KeyVaultConfigurationIncomplete); } if (string.IsNullOrEmpty(keyVaultClientSecret) && string.IsNullOrEmpty(keyVaultClientCert)) { Logger.LogError(CallInfo.Site(), "If KeyVaultUri is specified and managed identity is not used, KeyVault ClientSecret or KeyVault ClientCert must be specified"); return(ExitCode.KeyVaultConfigurationIncomplete); } if (!string.IsNullOrEmpty(keyVaultClientSecret)) { callback = (authority, resource, scope) => GetTokenFromClientSecretAsync(authority, resource, keyVaultClientId, keyVaultClientSecret); } else { X509Certificate2Collection keyVaultCerts = CertHelpers.FindCertificates(keyVaultClientCert, X509FindType.FindByThumbprint); if (keyVaultCerts.Count == 0) { Logger.LogError(CallInfo.Site(), "Failed to find Client cert with thumbprint '{0}'", keyVaultClientCert); return(ExitCode.KeyVaultConfigurationIncomplete); } callback = (authority, resource, scope) => GetTokenFromClientCertificateAsync(authority, resource, keyVaultClientId, keyVaultCerts[0]); } } keyVaultClient = new KeyVaultClient(callback); foreach (string keyVaultUri in keyVaultUris) { IPage <SecretItem> secrets = await keyVaultClient.GetSecretsAsync(keyVaultUri).ConfigureAwait(false); foreach (SecretItem secret in secrets) { keyVaultSecretMap[secret.Identifier.Name] = keyVaultUri; } while (!string.IsNullOrEmpty(secrets.NextPageLink)) { secrets = await keyVaultClient.GetSecretsNextAsync(secrets.NextPageLink).ConfigureAwait(false); foreach (SecretItem secret in secrets) { keyVaultSecretMap[secret.Identifier.Name] = keyVaultUri; } } } } // 2. Figure all the certs which need processing. string[] certsToConfigure = certConfiguration.Split(','); string currentExeDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string fullDirectoryPathForCerts = Path.Combine(currentExeDirectory, directoryPath); // 3. Process specified certs one by one. foreach (string certToConfigure in certsToConfigure) { // 3a. Split the cert configuration data to get actual details. This data is informat // <CertNameOnDisk>;CertSource(LocalMachine or KeyVault);<CertIdentifier(SecretName or Thumbprint)> string[] certConfigurationParams = certToConfigure.Split(';'); if (certConfigurationParams.Length != 3) { Logger.LogError(CallInfo.Site(), "Invalid certificate configuration '{0}'. Cert configuration must be in format <CertFileName>;<CertSource>;<CertIdentifier>", certToConfigure); return(ExitCode.InvalidCertConfiguration); } var certConfig = new { CertName = certConfigurationParams[0], CertSource = certConfigurationParams[1], CertIdentifier = certConfigurationParams[2] }; // 3b. Depending on the source of Cert get the PFX for the certs dropped into the directory. if (certConfig.CertSource.Equals("MyLocalMachine", StringComparison.OrdinalIgnoreCase)) { ExitCode localMachineCertHandler = await LocalMachineCertHandlerAsync( certConfig.CertName, certConfig.CertIdentifier, fullDirectoryPathForCerts).ConfigureAwait(false); if (localMachineCertHandler != ExitCode.Success) { return(localMachineCertHandler); } } else if (certConfig.CertSource.Equals("KeyVault", StringComparison.OrdinalIgnoreCase)) { if (!keyVaultSecretMap.TryGetValue(certConfig.CertIdentifier, out string keyVaultUri)) { Logger.LogError(CallInfo.Site(), "Certificate with name '{0}' missing from all specified KeyVaults", certConfig.CertIdentifier); return(ExitCode.CertificateMissingFromSource); } ExitCode keyVaultCertHandlerExitCode = await KeyVaultCertHandlerAsync( certConfig.CertName, certConfig.CertIdentifier, fullDirectoryPathForCerts, keyVaultClient, keyVaultUri).ConfigureAwait(false); if (keyVaultCertHandlerExitCode != ExitCode.Success) { return(keyVaultCertHandlerExitCode); } } else { Logger.LogError(CallInfo.Site(), "Unsupported Certificate source '{0}' for cert '{1}'", certConfig.CertSource, certConfig.CertName); return(ExitCode.UnsupportedCertSource); } // 3c. Convert PFX into .Key and .Crt. We are placing openssl next to this exe hence using current directory. ExitCode conversionExitCode = ConvertPfxIntoPemFormat(certConfig.CertName, fullDirectoryPathForCerts, currentExeDirectory, password: string.Empty); if (conversionExitCode != ExitCode.Success) { return(conversionExitCode); } // 3d. Delete the PFX as it is no longer needed. File.Delete(Path.Combine(fullDirectoryPathForCerts, certConfig.CertName + ".pfx")); } return(ExitCode.Success); }
public static void GetAllFromKeyVault(string vaultName, string appId, string appSecret) { if (string.IsNullOrWhiteSpace(vaultName)) { return; } KeyVaultClient keyClient; try { DelegatingHandler[] handler = { }; keyClient = new KeyVaultClient( async(authority, resource, scope) => { var adCredential = new ClientCredential(appId, appSecret); var authenticationContext = new AuthenticationContext(authority, null); var result = await authenticationContext.AcquireTokenAsync(resource, adCredential); return(result.AccessToken); }, handler); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); return; } string vaultUri = $"https://{vaultName.Trim()}.vault.azure.net"; try { // Actually for now, what I need is just the clientSecret //var clientSecret = keyClient.GetSecretAsync("MetagraphDataIngestionAppKatanaClientSecret"); var secretsResponseMessage = keyClient.GetSecretsAsync(vaultUri).Result; while (true) { using (var enumerator = secretsResponseMessage.GetEnumerator()) { while (enumerator.MoveNext()) { string secretUri = enumerator.Current.Id; try { var retrievedSecret = keyClient.GetSecretAsync(secretUri).Result; //this.AddSecret(retrievedSecret, vaultName); //Console.WriteLine(string.Format("{0}\t{1}", retrievedSecret, vaultName)); ShowSecret(retrievedSecret, vaultName); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } } } if (string.IsNullOrEmpty(secretsResponseMessage.NextPageLink)) { break; } secretsResponseMessage = keyClient.GetSecretsNextAsync(secretsResponseMessage.NextPageLink).Result; } } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } }