Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Arcus.BackgroundJobs.AzureActiveDirectory
{
/// <summary>
/// Represents the additional options that the user can configure during the <see cref="IServiceCollectionExtensions.AddClientSecretExpirationJob"/> call.
/// Represents the additional options that the user can configure during the <see cref="IServiceCollectionExtensions.AddClientSecretExpirationJob(IServiceCollection,Action{ClientSecretExpirationJobOptions})"/> call.
/// </summary>
public class ClientSecretExpirationJobOptions
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using System;
using Arcus.BackgroundJobs.AzureActiveDirectory;
using Arcus.EventGrid.Publishing.Interfaces;
using GuardNet;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
Expand All @@ -15,24 +19,63 @@ public static class IServiceCollectionExtensions
/// Adds the <see cref="ClientSecretExpirationJob"/> scheduled job
/// which will query Azure Active Directory for applications that have expired or soon to be expired secrets and send a CloudEvent to an Event Grid Topic.
/// </summary>
/// <remarks>
/// Make sure that the application has an Arcus EventGrid publisher configured.
/// For on the Arcus secret store: <a href="https://eventgrid.arcus-azure.net/Features/publishing-events" />.
/// </remarks>
/// <param name="services">The services to add the background job to.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> is <c>null</c>.</exception>
public static IServiceCollection AddClientSecretExpirationJob(this IServiceCollection services)
{
Guard.NotNull(services, nameof(services));
return AddClientSecretExpirationJob(services, configureOptions: null);
}

/// <summary>
/// Adds the <see cref="ClientSecretExpirationJob"/> scheduled job
/// which will query Azure Active Directory for applications that have expired or soon to be expired secrets and send a CloudEvent to an Event Grid Topic.
/// </summary>
/// <remarks>
/// Make sure that the application has an Arcus EventGrid publisher configured.
/// For on the Arcus secret store: <a href="https://eventgrid.arcus-azure.net/Features/publishing-events" />.
/// </remarks>
/// <param name="services">The services to add the background job to.</param>
/// <param name="configureOptions">The optional additional customized user configuration of options for this background job.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> is <c>null</c>.</exception>
public static IServiceCollection AddClientSecretExpirationJob(
this IServiceCollection services,
Action<ClientSecretExpirationJobOptions> configureOptions = null)
Action<ClientSecretExpirationJobOptions> configureOptions)
{
Guard.NotNull(services, nameof(services));

return services.AddScheduler(builder =>
{
builder.AddJob<ClientSecretExpirationJob, ClientSecretExpirationJobSchedulerOptions>(options =>
{
var additionalOptions = new ClientSecretExpirationJobOptions();
configureOptions?.Invoke(additionalOptions);
builder.AddJob<ClientSecretExpirationJob, ClientSecretExpirationJobSchedulerOptions>(
serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptionsMonitor<ClientSecretExpirationJobSchedulerOptions>>();
var publisher = serviceProvider.GetService<IEventGridPublisher>();
if (publisher is null)
{
throw new InvalidOperationException(
"Could not create a client secret expiration background job because no Arcus EventGrid publisher was registered in the application services, "
+ $"please add an '{nameof(IEventGridPublisher)}' instance to the registered services."
+ "For more information, see: https://eventgrid.arcus-azure.net/Features/publishing-events");
}

var logger =
serviceProvider.GetService<ILogger<ClientSecretExpirationJob>>()
?? NullLogger<ClientSecretExpirationJob>.Instance;

return new ClientSecretExpirationJob(options, publisher, logger);
},
options =>
{
var additionalOptions = new ClientSecretExpirationJobOptions();
configureOptions?.Invoke(additionalOptions);

options.SetUserOptions(additionalOptions);
});
options.SetUserOptions(additionalOptions);
});
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using CloudNative.CloudEvents;
using GuardNet;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
Expand All @@ -17,6 +20,11 @@ public static class IServiceCollectionExtensions
/// <summary>
/// Adds a background job to automatically refresh Azure App Configuration resources based on send-out App Configuration key-value events.
/// </summary>
/// <remarks>
/// Make sure that the application is configuring the Azure App Configuration when building the <see cref="IConfiguration"/> model
/// and that the Arcus secret store is configured correctly. For more information on Azure App Configuration: <a href="https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview" />
/// and on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive App Configuration events.</param>
/// <param name="serviceBusTopicConnectionStringSecretKey">The configuration key that points to the Azure Service Bus Topic connection string.</param>
Expand All @@ -39,10 +47,15 @@ public static IServiceCollection AddAutoRefreshAppConfigurationBackgroundJob(
serviceBusTopicConnectionStringSecretKey,
configureBackgroundJob: null);
}

/// <summary>
/// Adds a background job to automatically refresh Azure App Configuration resources based on send-out App Configuration key-value events.
/// </summary>
/// <remarks>
/// Make sure that the application is configuring the Azure App Configuration when building the <see cref="IConfiguration"/> model
/// and that the Arcus secret store is configured correctly. For more information on Azure App Configuration: <a href="https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview" />
/// and on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive App Configuration events.</param>
/// <param name="serviceBusTopicConnectionStringSecretKey">The configuration key that points to the Azure Service Bus Topic connection string.</param>
Expand All @@ -65,7 +78,25 @@ public static IServiceCollection AddAutoRefreshAppConfigurationBackgroundJob(
.AddCloudEventBackgroundJob(subscriptionNamePrefix, serviceBusTopicConnectionStringSecretKey, configureBackgroundJob)
.WithServiceBusMessageHandler<RefreshAppConfigurationMessageHandler, CloudEvent>(
messageBodyFilter: message => message?.Type is "Microsoft.AppConfiguration.KeyValueModified"
|| message?.Type is "Microsoft.AppConfiguration.KeyValueDeleted");
|| message?.Type is "Microsoft.AppConfiguration.KeyValueDeleted",
serviceProvider =>
{
var refresher = serviceProvider.GetService<IConfigurationRefresherProvider>();
if (refresher is null)
{
throw new InvalidOperationException(
"Cannot handle CloudEvents that notifies changes in the Azure App Configuration because no Azure App Configuration was registered with any refresh configuration registration. "
+ $"Please use the '{nameof(AzureAppConfigurationExtensions.AddAzureAppConfiguration)}' extension when building the {nameof(IConfiguration)} "
+ $"and configure a Azure App Configuration refresh '{nameof(IConfigurationRefresher)}' registration with the '{nameof(AzureAppConfigurationOptions.ConfigureRefresh)}' extension."
+ "For more information on Azure App Configuration: https://docs.microsoft.com/en-us/azure/azure-app-configuration/");
}

var logger =
serviceProvider.GetService<ILogger<RefreshAppConfigurationMessageHandler>>()
?? NullLogger<RefreshAppConfigurationMessageHandler>.Instance;

return new RefreshAppConfigurationMessageHandler(refresher, logger);
});

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public static class IServiceCollectionExtensions
/// <summary>
/// Adds a background job to the <see cref="IServiceCollection"/> to receive <see cref="CloudEvent"/>'s.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="topicName"></param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive <see cref="CloudEvent"/>'s.</param>
Expand All @@ -43,6 +47,10 @@ public static ServiceBusMessageHandlerCollection AddCloudEventBackgroundJob(
/// <summary>
/// Adds a background job to the <see cref="IServiceCollection"/> to receive <see cref="CloudEvent"/>'s.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="topicName"></param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive <see cref="CloudEvent"/>'s.</param>
Expand Down Expand Up @@ -72,6 +80,10 @@ public static ServiceBusMessageHandlerCollection AddCloudEventBackgroundJob(
/// <summary>
/// Adds a background job to the <see cref="IServiceCollection"/> to receive <see cref="CloudEvent"/>'s.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive <see cref="CloudEvent"/>'s.</param>
/// <param name="serviceBusTopicConnectionStringSecretKey">The secret key that points to the Azure Service Bus Topic-scoped connection string.</param>
Expand All @@ -94,6 +106,10 @@ public static ServiceBusMessageHandlerCollection AddCloudEventBackgroundJob(
/// <summary>
/// Adds a background job to the <see cref="IServiceCollection"/> to receive <see cref="CloudEvent"/>'s.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services collection to add the job to.</param>
/// <param name="subscriptionNamePrefix">The name of the Azure Service Bus subscription that will be created to receive <see cref="CloudEvent"/>'s.</param>
/// <param name="serviceBusTopicConnectionStringSecretKey">The secret key that points to the Azure Service Bus Topic-scoped connection string.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ public string BaseUrl
}

/// <summary>
/// Gets or sets the secret key to retrieve the token from the registered <see cref="ISecretProvider"/>.
/// Gets or sets the secret key to retrieve the token from the registered Arcus secret store.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <exception cref="ArgumentException">Thrown when <paramref name="value"/> is blank.</exception>
public string TokenSecretKey
{
Expand Down Expand Up @@ -64,6 +68,10 @@ internal void SetUserOptions(DatabricksJobMetricsJobOptions options)
/// <summary>
/// Creates an <see cref="DatabricksClient"/> instance using the predefined values.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="secretProvider">The provider to retrieve the token during the creation of the instance.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="secretProvider"/> is <c>null</c>.</exception>
public virtual async Task<DatabricksClient> CreateDatabricksClientAsync(ISecretProvider secretProvider)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using System;
using Arcus.BackgroundJobs.Databricks;
using Arcus.Security.Core;
using GuardNet;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
Expand All @@ -15,6 +20,10 @@ public static class IServiceCollectionExtensions
/// Adds the <see cref="DatabricksJobMetricsJob"/> scheduled job
/// which will query for finished Databricks job runs on a specified interval and report them as metrics.
/// </summary>
/// <remarks>
/// Make sure that the application has the Arcus secret store configured correctly.
/// For on the Arcus secret store: <a href="https://security.arcus-azure.net/features/secret-store" />.
/// </remarks>
/// <param name="services">The services to add the background job to.</param>
/// <param name="baseUrl">The URL where the Databricks instance is located on Azure.</param>
/// <param name="tokenSecretKey">The secret key that points to the token to authenticate with the Databricks instance.</param>
Expand All @@ -33,15 +42,35 @@ public static IServiceCollection AddDatabricksJobMetricsJob(

return services.AddScheduler(builder =>
{
builder.AddJob<DatabricksJobMetricsJob, DatabricksJobMetricsJobSchedulerOptions>(options =>
{
var additionalOptions = new DatabricksJobMetricsJobOptions();
configureOptions?.Invoke(additionalOptions);
builder.AddJob<DatabricksJobMetricsJob, DatabricksJobMetricsJobSchedulerOptions>(
serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptionsMonitor<DatabricksJobMetricsJobSchedulerOptions>>();
var secretProvider = serviceProvider.GetService<ISecretProvider>();
if (secretProvider is null)
{
throw new InvalidOperationException(
"Could not register the Databricks background job to measure finished job runs because no Arcus secret store was registered to retrieve the access token to interact with the Databricks instance,"
+ $"please configure the Arcus secret store with '{nameof(IHostBuilderExtensions.ConfigureSecretStore)}' on the application '{nameof(IHost)}' "
+ $"or during the service collection registration by calling 'AddSecretStore' on the application '{nameof(IServiceCollection)}'."
+ "For more information on the Arcus secret store, see: https://security.arcus-azure.net/features/secret-store");
}

options.BaseUrl = baseUrl;
options.TokenSecretKey = tokenSecretKey;
options.SetUserOptions(additionalOptions);
});
var logger =
serviceProvider.GetService<ILogger<DatabricksJobMetricsJob>>()
?? NullLogger<DatabricksJobMetricsJob>.Instance;

return new DatabricksJobMetricsJob(options, secretProvider, logger);
},
options =>
{
var additionalOptions = new DatabricksJobMetricsJobOptions();
configureOptions?.Invoke(additionalOptions);

options.BaseUrl = baseUrl;
options.TokenSecretKey = tokenSecretKey;
options.SetUserOptions(additionalOptions);
});
});
}
}
Expand Down
Loading