Skip to content

Commit 2d1334c

Browse files
Merge pull request #2 from Anders-Toegersen/feature/introduce-managed-identity-configuration
Introduce Managed Identity configuration
2 parents b9360a0 + 72ccef0 commit 2d1334c

26 files changed

+449
-70
lines changed

.editorconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,4 +506,5 @@ dotnet_diagnostic.S1135.severity = suggestion # https://github.com/atc-net
506506
dotnet_diagnostic.CA1062.severity = none # Do not demand null-checking when using nullable reference types.
507507
dotnet_diagnostic.SA1011.severity = none # Space needed after closing square bracet "]" needed for nullable arrays
508508
dotnet_diagnostic.SA1401.severity = none # Field should be private
509-
dotnet_diagnostic.CA1051.severity = none # Do not declare visible instance fields
509+
dotnet_diagnostic.CA1051.severity = none # Do not declare visible instance fields
510+
dotnet_diagnostic.CA1812.severity = none # Internal classes are instantiated by IoC

Atc.Azure.Messaging.sln

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
2-
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 17
4-
VisualStudioVersion = 17.0.31903.59
5-
MinimumVisualStudioVersion = 15.0.26124.0
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging", "src\Atc.Azure.Messaging\Atc.Azure.Messaging.csproj", "{2F7702F2-A407-41FB-8C88-7C066237BC75}"
7-
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging.Tests", "test\Atc.Azure.Messaging.Tests\Atc.Azure.Messaging.Tests.csproj", "{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}"
9-
EndProject
10-
Global
11-
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12-
Debug|Any CPU = Debug|Any CPU
13-
Release|Any CPU = Release|Any CPU
14-
EndGlobalSection
15-
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.Build.0 = Debug|Any CPU
18-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.ActiveCfg = Release|Any CPU
19-
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.Build.0 = Release|Any CPU
20-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23-
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.Build.0 = Release|Any CPU
24-
EndGlobalSection
25-
GlobalSection(SolutionProperties) = preSolution
26-
HideSolutionNode = FALSE
27-
EndGlobalSection
28-
GlobalSection(ExtensibilityGlobals) = postSolution
29-
SolutionGuid = {1EC093F7-1E03-4088-BA72-0DEB39AFEE82}
30-
EndGlobalSection
31-
EndGlobal
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging", "src\Atc.Azure.Messaging\Atc.Azure.Messaging.csproj", "{2F7702F2-A407-41FB-8C88-7C066237BC75}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Atc.Azure.Messaging.Tests", "test\Atc.Azure.Messaging.Tests\Atc.Azure.Messaging.Tests.csproj", "{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{2F7702F2-A407-41FB-8C88-7C066237BC75}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{0C49EE44-DAE3-4A7C-9D2D-D1190CAC85F0}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {1EC093F7-1E03-4088-BA72-0DEB39AFEE82}
30+
EndGlobalSection
31+
EndGlobal

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,46 @@ builder.Services.AddSwaggerGen();
3737
builder.Services.ConfigureMessagingServices(builder.Configuration);
3838
```
3939

40+
## Connecting with Managed Identity
41+
42+
When connecting with Managed Identity you need to setup your configuration accordingly.
43+
44+
The following is an example of how you would configure your EventHub or ServiceBus with Managed Identity for [ATC Azure Options](https://github.com/atc-net/atc-azure-options)
45+
46+
```json
47+
{
48+
"EventHubOptions": {
49+
"FullyQualifiedNamespace": "[your eventhub namespace].servicebus.windows.net"
50+
},
51+
"ServiceBusOptions": {
52+
"FullyQualifiedNamespace": "[your servicebus namespace].servicebus.windows.net"
53+
},
54+
"ClientAuthorizationOptions": {
55+
"TenantId": "[your tenant id]"
56+
},
57+
"EnvironmentOptions": {
58+
"EnvironmentType": "[Local/DevTest/Production]"
59+
}
60+
}
61+
```
62+
63+
It is important that the logged-in user/application has the `Azure Service Bus Data Sender` or `Azure Service Bus Data Owner` build-in role for [ServiceBus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-managed-service-identity#azure-built-in-roles-for-azure-service-bus).
64+
65+
And the corresponding `Azure Event Hubs Data Sender` or `Azure Event Hubs Data Owner` build-in roles for [Eventhubs](https://learn.microsoft.com/en-us/azure/event-hubs/authenticate-application#built-in-roles-for-azure-event-hubs)
66+
67+
The dependencies are registered using `ConfigureMessagingServices(IConfiguration, bool)` for the default implementation of [IAzureCredentialOptionsProvider](https://github.com/atc-net/atc-azure-options/blob/main/src/Atc.Azure.Options/Providers/AzureCredentialOptionsProvider.cs) and `ConfigureMessagingServices(IConfiguration, bool, IAzureCredentialOptionsProvider)` if you wish to use your own implementation of `IAzureCredentialOptionsProvider`.
68+
69+
Here's an example of the default implementation using a Minimal API setup
70+
71+
```csharp
72+
var builder = WebApplication.CreateBuilder(args);
73+
builder.Services.AddEndpointsApiExplorer();
74+
builder.Services.AddSwaggerGen();
75+
76+
// Register Atc.Azure.Messaging dependencies
77+
builder.Services.ConfigureMessagingServices(builder.Configuration, true);
78+
```
79+
4080
## Publishing to EventHub
4181

4282
To publish events to an EventHub you need an instance of `IEventHubPublisher`, this can be constructed via the `IEventHubPublisherFactory` which exposes the `Create(string eventHubName)` method

sample/SampleApi/Program.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
builder.Services.AddSingleton<SendDataHandler>();
1313

1414
// Register Atc.Azure.Messaging dependencies
15-
builder.Services.ConfigureMessagingServices(builder.Configuration);
15+
var useManagedIdentity = false;
16+
builder.Services.ConfigureMessagingServices(builder.Configuration, useManagedIdentity);
1617

1718
var app = builder.Build();
1819
app.UseHttpsRedirection();
@@ -38,15 +39,14 @@ public SendDataHandler(
3839
IEventHubPublisherFactory eventHubFactory,
3940
IServiceBusPublisher serviceBusPublisher)
4041
{
41-
eventHubPublisher = eventHubFactory.Create("[existing eventhub");
42+
eventHubPublisher = eventHubFactory.Create("[existing eventhub]");
4243
this.serviceBusPublisher = serviceBusPublisher;
4344
}
4445

4546
public async Task<Response> Post(Request request)
4647
{
4748
await eventHubPublisher.PublishAsync(request);
48-
49-
await serviceBusPublisher.PublishAsync("existing topic|queue", request);
49+
await serviceBusPublisher.PublishAsync("[existing topic|queue]", request);
5050

5151
return new Response(
5252
Guid.NewGuid().ToString("N"),

sample/SampleApi/appsettings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,14 @@
88
"AllowedHosts": "*",
99
"EventHubOptions": {
1010
"ConnectionString": "Endpoint=sb://[your eventhub namespace].servicebus.windows.net/;SharedAccessKeyName=[eventhub name];SharedAccessKey=[sas key]"
11+
},
12+
"ServiceBusOptions": {
13+
"FullyQualifiedNamespace": "[your servicebus namespace].servicebus.windows.net"
14+
},
15+
"ClientAuthorizationOptions": {
16+
"TenantId": "[your tenant id]"
17+
},
18+
"EnvironmentOptions": {
19+
"EnvironmentType": "Local"
1120
}
1221
}

src/Atc.Azure.Messaging/Atc.Azure.Messaging.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<None Include="..\..\README.md" Pack="true" PackagePath="\"/>
14+
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
1515
</ItemGroup>
1616

1717
<ItemGroup>
18-
<PackageReference Include="Atc.Azure.Options" Version="3.0.14" />
18+
<PackageReference Include="Atc.Azure.Options" Version="3.0.18" />
1919
<PackageReference Include="Azure.Messaging.EventHubs" Version="5.7.0" />
2020
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.8.1" />
2121
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using Atc.Azure.Options.Authorization;
3+
using Atc.Azure.Options.Environment;
4+
using Atc.Azure.Options.EventHub;
5+
using Atc.Azure.Options.Providers;
6+
using Azure.Identity;
7+
using Azure.Messaging.EventHubs.Producer;
8+
9+
namespace Atc.Azure.Messaging.EventHub;
10+
11+
[SuppressMessage(
12+
"Reliability",
13+
"CA2000:Dispose objects before losing scope",
14+
Justification = "EventHubPublisher is responsible for disposing EventHubProducerClient")]
15+
internal sealed class EventHubCredentialsPublisherFactory : IEventHubPublisherFactory
16+
{
17+
private readonly string fullyQualifiedNamespace;
18+
private readonly DefaultAzureCredentialOptions credentialOptions;
19+
20+
public EventHubCredentialsPublisherFactory(
21+
EventHubOptions options,
22+
EnvironmentOptions environmentOptions,
23+
ClientAuthorizationOptions clientCredentialOptions,
24+
IAzureCredentialOptionsProvider credentialOptionsProvider)
25+
{
26+
this.fullyQualifiedNamespace = options.FullyQualifiedNamespace;
27+
this.credentialOptions = credentialOptionsProvider
28+
.GetAzureCredentialOptions(
29+
environmentOptions,
30+
clientCredentialOptions);
31+
}
32+
33+
public IEventHubPublisher Create(string eventHubName)
34+
=> new EventHubPublisher(
35+
new EventHubProducerClient(
36+
fullyQualifiedNamespace,
37+
eventHubName,
38+
new DefaultAzureCredential(credentialOptions)));
39+
}

src/Atc.Azure.Messaging/EventHub/EventHubPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Atc.Azure.Messaging.EventHub;
77

8-
public sealed class EventHubPublisher : IEventHubPublisher
8+
internal sealed class EventHubPublisher : IEventHubPublisher
99
{
1010
private readonly EventHubProducerClient client;
1111

src/Atc.Azure.Messaging/EventHub/EventHubPublisherFactory.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using Atc.Azure.Options.EventHub;
23
using Azure.Messaging.EventHubs.Producer;
34

45
namespace Atc.Azure.Messaging.EventHub;
56

6-
#pragma warning disable CA2000 // Dispose objects before losing scope
7-
8-
public class EventHubPublisherFactory : IEventHubPublisherFactory
7+
[SuppressMessage(
8+
"Reliability",
9+
"CA2000:Dispose objects before losing scope",
10+
Justification = "EventHubPublisher is responsible for disposing EventHubProducerClient")]
11+
internal sealed class EventHubPublisherFactory : IEventHubPublisherFactory
912
{
1013
private readonly string connectionString;
1114

src/Atc.Azure.Messaging/EventHub/IEventHubPublisher.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
namespace Atc.Azure.Messaging.EventHub;
1+
namespace Atc.Azure.Messaging.EventHub;
22

3+
/// <summary>
4+
/// Publisher responsible for publishing objects with metadata to a specific EventHub.
5+
/// </summary>
6+
/// <remarks>
7+
/// Is safe to cache and use in singletons for the lifetime of the application.
8+
/// </remarks>
39
public interface IEventHubPublisher : IAsyncDisposable
410
{
511
Task PublishAsync(

0 commit comments

Comments
 (0)