private static async Task <IKeyVaultClient> CreateKeyVaultClientAsync(KeyRotationConfig rotationConfig)
        {
            ServicePrincipalAuthentication authentication = rotationConfig.ServicePrincipal.CreateAuthentication();
            IKeyVaultClient keyVaultClient = await authentication.AuthenticateAsync();

            return(keyVaultClient);
        }
Beispiel #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceBusConfiguration"/> class.
        /// </summary>
        /// <param name="configuration">The configuration instance to provide the necessary information during authentication with the correct Azure Service Bus instance.</param>
        /// <param name="logger">The instance to log diagnostic messages during the interaction with the Azure Service Bus instance.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="configuration"/> or the <paramref name="logger"/> is <c>null</c>.</exception>
        public ServiceBusConfiguration(KeyRotationConfig configuration, ILogger logger)
        {
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(logger, nameof(logger));

            _configuration = configuration;
            _logger        = logger;
        }
 private static void AddServiceBusMessagePump(WorkerOptions options, KeyRotationConfig rotationConfig, string jobId)
 {
     options.AddServiceBusQueueMessagePump(rotationConfig.KeyVault.SecretName, opt =>
     {
         opt.JobId = jobId;
         // Unrealistic big maximum exception count so that we're certain that the message pump gets restarted based on the notification and not the unauthorized exception.
         opt.MaximumUnauthorizedExceptionsBeforeRestart = 1000;
     }).WithServiceBusMessageHandler <OrdersAzureServiceBusMessageHandler, Order>();
 }
 private static void AddSecretStore(WorkerOptions options, KeyRotationConfig rotationConfig)
 {
     options.Configure(host => host.ConfigureSecretStore((configuration, stores) =>
     {
         stores.AddAzureKeyVaultWithServicePrincipal(
             rotationConfig.KeyVault.VaultUri,
             rotationConfig.ServicePrincipal.ClientId,
             rotationConfig.ServicePrincipal.ClientSecret)
         .AddConfiguration(configuration);
     }));
 }
        public async Task ServiceBusMessagePump_RotateServiceBusConnectionKeysOnSecretNewVersionNotification_MessagePumpRestartsThenMessageSuccessfullyProcessed()
        {
            // Arrange
            var config = TestConfig.Create();
            KeyRotationConfig rotationConfig = config.GetKeyRotationConfig();

            _logger.LogInformation("Using Service Principal [ClientID: '{0}']", rotationConfig.ServicePrincipal.ClientId);

            var    client = new ServiceBusConfiguration(rotationConfig, _logger);
            string freshConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.PrimaryKey);

            IKeyVaultClient keyVaultClient = await CreateKeyVaultClientAsync(rotationConfig);

            await SetConnectionStringInKeyVaultAsync(keyVaultClient, rotationConfig, freshConnectionString);

            string       jobId = Guid.NewGuid().ToString();
            const string connectionStringSecretKey = "ARCUS_KEYVAULT_SECRETNEWVERSIONCREATED_CONNECTIONSTRING";

            var options = new WorkerOptions();

            options.Configuration.Add(connectionStringSecretKey, rotationConfig.KeyVault.SecretNewVersionCreated.ConnectionString);
            AddEventGridPublisher(options, config);
            AddSecretStore(options, rotationConfig);
            AddServiceBusMessagePump(options, rotationConfig, jobId);

            options.AddAutoRestartServiceBusMessagePumpOnRotatedCredentialsBackgroundJob(
                jobId: jobId,
                subscriptionNamePrefix: "TestSub",
                serviceBusTopicConnectionStringSecretKey: connectionStringSecretKey,
                messagePumpConnectionStringKey: rotationConfig.KeyVault.SecretName);

            await using (var worker = await Worker.StartNewAsync(options))
            {
                string newSecondaryConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.SecondaryKey);
                await SetConnectionStringInKeyVaultAsync(keyVaultClient, rotationConfig, newSecondaryConnectionString);

                await using (var service = await TestMessagePumpService.StartNewAsync(config, _logger))
                {
                    // Act
                    string newPrimaryConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.PrimaryKey);

                    // Assert
                    await service.SimulateMessageProcessingAsync(newPrimaryConnectionString);
                }
            }
        }
Beispiel #6
0
        public async Task ServiceBusMessagePump_RotateServiceBusConnectionKeys_MessagePumpRestartsThenMessageSuccessfullyProcessed()
        {
            // Arrange
            var config = TestConfig.Create();
            KeyRotationConfig keyRotationConfig = config.GetKeyRotationConfig();

            _logger.LogInformation("Using Service Principal [ClientID: '{ClientId}']", keyRotationConfig.ServicePrincipal.ClientId);

            var    client = new ServiceBusConfiguration(keyRotationConfig, _logger);
            string freshConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.PrimaryKey);

            ServicePrincipalAuthentication authentication = keyRotationConfig.ServicePrincipal.CreateAuthentication();
            IKeyVaultClient keyVaultClient = await authentication.AuthenticateAsync();

            await SetConnectionStringInKeyVaultAsync(keyVaultClient, keyRotationConfig, freshConnectionString);

            var options = new WorkerOptions();

            options.AddEventGridPublisher(config)
            .AddSingleton <ISecretProvider>(serviceProvider =>
            {
                return(new KeyVaultSecretProvider(
                           new ServicePrincipalAuthentication(keyRotationConfig.ServicePrincipal.ClientId,
                                                              keyRotationConfig.ServicePrincipal.ClientSecret),
                           new KeyVaultConfiguration(keyRotationConfig.KeyVault.VaultUri)));
            })
            .AddServiceBusQueueMessagePump(keyRotationConfig.KeyVault.SecretName, opt => opt.AutoComplete = true)
            .WithServiceBusMessageHandler <OrdersAzureServiceBusMessageHandler, Order>();

            await using (var worker = await Worker.StartNewAsync(options))
            {
                string newSecondaryConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.SecondaryKey);
                await SetConnectionStringInKeyVaultAsync(keyVaultClient, keyRotationConfig, newSecondaryConnectionString);

                await using (var service = await TestMessagePumpService.StartNewAsync(config, _logger))
                {
                    // Act
                    string newPrimaryConnectionString = await client.RotateConnectionStringKeysForQueueAsync(KeyType.PrimaryKey);

                    // Assert
                    await service.SimulateMessageProcessingAsync(newPrimaryConnectionString);
                }
            }
        }
Beispiel #7
0
        public async Task RotateServiceBusSecrets_WithValidArguments_RotatesPrimarySecondaryAlternatively()
        {
            // Arrange
            var config = TestConfig.Create();
            KeyRotationConfig keyRotationConfig = config.GetKeyRotationConfig();

            _logger.LogInformation("Using Service Principal [ClientID: '{ClientId}']", keyRotationConfig.ServicePrincipal.ClientId);
            const ServiceBusEntityType entity = ServiceBusEntityType.Topic;

            var keyVaultAuthentication = new ServicePrincipalAuthentication(
                keyRotationConfig.ServicePrincipal.ClientId,
                keyRotationConfig.ServicePrincipal.ClientSecret);

            var keyVaultConfiguration = new KeyVaultConfiguration(keyRotationConfig.KeyVault.VaultUri);
            var secretProvider        = new KeyVaultSecretProvider(keyVaultAuthentication, keyVaultConfiguration);

            AzureServiceBusClient azureServiceBusClient = CreateAzureServiceBusClient(keyRotationConfig, secretProvider, entity);
            var rotation = new AzureServiceBusKeyRotation(azureServiceBusClient, keyVaultAuthentication, keyVaultConfiguration, _logger);

            var        client = new ServiceBusConfiguration(keyRotationConfig, _logger);
            AccessKeys keysBefore1stRotation = await client.GetConnectionStringKeysForTopicAsync();

            // Act
            await rotation.RotateServiceBusSecretAsync(keyRotationConfig.KeyVault.SecretName);

            // Assert
            string secondaryConnectionString = await secretProvider.GetRawSecretAsync(keyRotationConfig.KeyVault.SecretName);

            AccessKeys keysAfter1stRotation = await client.GetConnectionStringKeysForTopicAsync();

            Assert.True(secondaryConnectionString == keysAfter1stRotation.SecondaryConnectionString, "Secondary connection string should be set in Azure Key Vault after first rotation");
            Assert.NotEqual(keysBefore1stRotation.PrimaryConnectionString, keysAfter1stRotation.PrimaryConnectionString);
            Assert.NotEqual(keysBefore1stRotation.SecondaryConnectionString, keysAfter1stRotation.SecondaryConnectionString);

            await rotation.RotateServiceBusSecretAsync(keyRotationConfig.KeyVault.SecretName);

            string primaryConnectionString = await secretProvider.GetRawSecretAsync(keyRotationConfig.KeyVault.SecretName);

            AccessKeys keysAfter2ndRotation = await client.GetConnectionStringKeysForTopicAsync();

            Assert.True(primaryConnectionString == keysAfter2ndRotation.PrimaryConnectionString, "Primary connection string should be set in Azure Key Vault after second rotation");
            Assert.NotEqual(keysAfter1stRotation.PrimaryConnectionString, keysAfter2ndRotation.PrimaryConnectionString);
            Assert.NotEqual(keysAfter2ndRotation.SecondaryConnectionString, keysAfter1stRotation.SecondaryConnectionString);
        }
Beispiel #8
0
        private AzureServiceBusClient CreateAzureServiceBusClient(
            KeyRotationConfig keyRotationConfig,
            ISecretProvider secretProvider,
            ServiceBusEntityType entity)
        {
            var serviceBusAuthentication = new DefaultAzureServiceBusManagementAuthentication(
                keyRotationConfig.ServicePrincipal.ClientId,
                keyRotationConfig.ServicePrincipal.ClientSecretKey,
                keyRotationConfig.ServiceBusNamespace.SubscriptionId,
                keyRotationConfig.ServiceBusNamespace.TenantId,
                secretProvider);

            var serviceBusLocation = new AzureServiceBusNamespace(
                keyRotationConfig.ServiceBusNamespace.ResourceGroup,
                keyRotationConfig.ServiceBusNamespace.Namespace,
                entity,
                keyRotationConfig.ServiceBusNamespace.TopicName,
                keyRotationConfig.ServiceBusNamespace.AuthorizationRuleName);

            var azureServiceBusClient = new AzureServiceBusClient(serviceBusAuthentication, serviceBusLocation, _logger);

            return(azureServiceBusClient);
        }
Beispiel #9
0
 private static async Task SetConnectionStringInKeyVaultAsync(IKeyVaultClient keyVaultClient, KeyRotationConfig keyRotationConfig, string rotatedConnectionString)
 {
     await keyVaultClient.SetSecretAsync(
         vaultBaseUrl : keyRotationConfig.KeyVault.VaultUri,
         secretName : keyRotationConfig.KeyVault.SecretName,
         value : rotatedConnectionString);
 }