private async Task <Dictionary <string, string> > TryRetrieveKeyVaultSecretsAsync(CancellationToken token, StringBuilder errorBuilder)
        {
            var keyVaultSettingsString = _distributedSettings.KeyVaultSettingsString;

            if (keyVaultSettingsString is null && _redisContentSecretNames.KeyVaultSecretName is null)
            {
                errorBuilder.Append(
                    $"Either {nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.KeyVaultSettingsString)} or {nameof(RedisContentSecretNames)}.{nameof(RedisContentSecretNames.KeyVaultSecretName)} should be specified. ");
                return(null);
            }

            if (keyVaultSettingsString is null && _redisContentSecretNames.KeyVaultSecretName != null)
            {
                var keyVaultSettingsStringProvider = new HostConnectionStringProvider(_arguments.Host, _redisContentSecretNames.KeyVaultSecretName, _logger);
                var keyVaultSettingsStringResult   = await keyVaultSettingsStringProvider.GetConnectionString();

                if (!keyVaultSettingsStringResult.Succeeded)
                {
                    errorBuilder.Append($"Unable to get key vault settings string: {keyVaultSettingsStringResult}. ");
                    return(null);
                }

                keyVaultSettingsString = keyVaultSettingsStringResult.ConnectionString;
            }

            _logger.Debug($"KeyVaultSettingsString: <non-null secret>, "
                          + $"EventHubSecretName: {_distributedSettings.EventHubSecretName}, AzureStorageSecretName: {_distributedSettings.AzureStorageSecretName}, GlobalRedisSecretName: {_distributedSettings.GlobalRedisSecretName}, SecondaryGlobalRedisSecretName: {_distributedSettings.SecondaryGlobalRedisSecretName}.");

            bool invalidConfiguration = appendIfNull(_distributedSettings.EventHubSecretName, $"{nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.EventHubSecretName)}");

            invalidConfiguration |= appendIfNull(_distributedSettings.GlobalRedisSecretName, $"{nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.GlobalRedisSecretName)}");

            if (invalidConfiguration)
            {
                return(null);
            }

            var storageSecretNames = GetAzureStorageSecretNames(errorBuilder);

            if (storageSecretNames == null)
            {
                return(null);
            }

            if (_distributedSettings.EventHubSecretName != null &&
                _distributedSettings.GlobalRedisSecretName != null)
            {
                var retryPolicy = CreateKeyVaultRetryPolicy(_distributedSettings);
                return(await retryPolicy.ExecuteAsync(
                           async() =>
                {
                    return await _arguments.Host.RetrieveKeyVaultSecretsAsync(
                        new List <string>(storageSecretNames)
                    {
                        _distributedSettings.EventHubSecretName,
                        _distributedSettings.GlobalRedisSecretName,
                        _distributedSettings.SecondaryGlobalRedisSecretName
                    }.Where(s => s != null).ToList(),
                        token);
                },
                           token));
            }

            return(null);

            bool appendIfNull(object value, string propertyName)
            {
                if (value is null)
                {
                    errorBuilder.Append($"{propertyName} should be provided. ");
                    return(true);
                }

                return(false);
            }
        }
Example #2
0
        private async Task <Dictionary <string, string> > TryRetrieveKeyVaultSecretsAsync(CancellationToken token, StringBuilder errorBuilder)
        {
            var keyVaultSettingsString = _distributedSettings.KeyVaultSettingsString;

            if (keyVaultSettingsString is null && _redisContentSecretNames.KeyVaultSecretName is null)
            {
                errorBuilder.Append(
                    $"Either {nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.KeyVaultSettingsString)} or {nameof(RedisContentSecretNames)}.{nameof(RedisContentSecretNames.KeyVaultSecretName)} should be specified. ");
                return(null);
            }

            if (keyVaultSettingsString is null && _redisContentSecretNames.KeyVaultSecretName != null)
            {
                var keyVaultSettingsStringProvider = new HostConnectionStringProvider(_arguments.Host, _redisContentSecretNames.KeyVaultSecretName, _logger);
                var keyVaultSettingsStringResult   = await keyVaultSettingsStringProvider.GetConnectionString();

                if (!keyVaultSettingsStringResult.Succeeded)
                {
                    errorBuilder.Append($"Unable to get key vault settings string: {keyVaultSettingsStringResult}. ");
                    return(null);
                }

                keyVaultSettingsString = keyVaultSettingsStringResult.ConnectionString;
            }

            _logger.Debug($"KeyVaultSettingsString: <non-null secret>, "
                          + $"EventHubSecretName: {_distributedSettings.EventHubSecretName}, AzureStorageSecretName: {_distributedSettings.AzureStorageSecretName}, GlobalRedisSecretName: {_distributedSettings.GlobalRedisSecretName}, SecondaryGlobalRedisSecretName: {_distributedSettings.SecondaryGlobalRedisSecretName}.");

            bool invalidConfiguration = appendIfNull(_distributedSettings.EventHubSecretName, $"{nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.EventHubSecretName)}");

            invalidConfiguration |= appendIfNull(_distributedSettings.GlobalRedisSecretName, $"{nameof(DistributedContentSettings)}.{nameof(DistributedContentSettings.GlobalRedisSecretName)}");

            if (invalidConfiguration)
            {
                return(null);
            }

            var storageSecretNames = GetAzureStorageSecretNames(errorBuilder);

            if (storageSecretNames == null)
            {
                return(null);
            }

            if (_distributedSettings.EventHubSecretName != null &&
                _distributedSettings.GlobalRedisSecretName != null)
            {
                try
                {
                    return(await _arguments.Host.RetrieveKeyVaultSecretsAsync(
                               new List <string>(storageSecretNames)
                    {
                        _distributedSettings.EventHubSecretName,
                        _distributedSettings.GlobalRedisSecretName,
                        _distributedSettings.SecondaryGlobalRedisSecretName
                    }.Where(s => s != null).ToList(),
                               token));
                }
                // In some cases, KeyVault provider may fail with HttpRequestException with an inner exception like 'The remote name could not be resolved: 'login.windows.net'.
                // Theoretically, this should be handled by the host, but to make error handling simple and consistent (this method throws one exception type) the handling is happening here.
                catch (Exception e) when(e.Message.Contains("The remote name could not be resolved"))
                {
                    errorBuilder.Append($"Unable to get key vault settings because the key vault server is unavailable. Exception: {e}. ");
                    return(null);
                }
            }

            return(null);

            bool appendIfNull(object value, string propertyName)
            {
                if (value is null)
                {
                    errorBuilder.Append($"{propertyName} should be provided. ");
                    return(true);
                }

                return(false);
            }
        }