Skip to content

Commit 3b3f942

Browse files
authored
Roles refactor using CDK Resolvers (Azure#47285)
1 parent fc1a231 commit 3b3f942

14 files changed

+693
-249
lines changed

sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.net8.0.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public abstract partial class CloudMachineFeature
8787
protected CloudMachineFeature() { }
8888
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
8989
public Azure.Provisioning.Primitives.ProvisionableResource Emitted { get { throw null; } protected set { } }
90+
protected internal System.Collections.Generic.Dictionary<Azure.Provisioning.Primitives.Provisionable, (string RoleName, string RoleId)[]> RequiredSystemRoles { get { throw null; } }
9091
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
9192
public virtual void AddTo(Azure.CloudMachine.CloudMachineInfrastructure cm) { }
9293
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]

sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public abstract partial class CloudMachineFeature
8787
protected CloudMachineFeature() { }
8888
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
8989
public Azure.Provisioning.Primitives.ProvisionableResource Emitted { get { throw null; } protected set { } }
90+
protected internal System.Collections.Generic.Dictionary<Azure.Provisioning.Primitives.Provisionable, (string RoleName, string RoleId)[]> RequiredSystemRoles { get { throw null; } }
9091
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
9192
public virtual void AddTo(Azure.CloudMachine.CloudMachineInfrastructure cm) { }
9293
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]

sdk/provisioning/Azure.Provisioning.CloudMachine/src/AzureSdkExtensions/KeyVaultFeature.cs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using System.Collections.Generic;
45
using Azure.Provisioning.Authorization;
56
using Azure.Provisioning.CloudMachine;
67
using Azure.Provisioning.Expressions;
@@ -44,20 +45,8 @@ protected override ProvisionableResource EmitCore(CloudMachineInfrastructure inf
4445
]
4546
},
4647
};
47-
4848
infrastructure.AddResource(keyVaultResource);
49-
50-
RoleAssignment ra = keyVaultResource.CreateRoleAssignment(KeyVaultBuiltInRole.KeyVaultAdministrator, RoleManagementPrincipalType.User, infrastructure.PrincipalIdParameter);
51-
infrastructure.AddResource(ra);
52-
53-
// necessary until ResourceName is settable via AssignRole.
54-
RoleAssignment kvMiRoleAssignment = new RoleAssignment(keyVaultResource.BicepIdentifier + "_" + infrastructure.Identity.BicepIdentifier + "_" + KeyVaultBuiltInRole.GetBuiltInRoleName(KeyVaultBuiltInRole.KeyVaultAdministrator));
55-
kvMiRoleAssignment.Name = BicepFunction.CreateGuid(keyVaultResource.Id, infrastructure.Identity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", KeyVaultBuiltInRole.KeyVaultAdministrator.ToString()));
56-
kvMiRoleAssignment.Scope = new IdentifierExpression(keyVaultResource.BicepIdentifier);
57-
kvMiRoleAssignment.PrincipalType = RoleManagementPrincipalType.ServicePrincipal;
58-
kvMiRoleAssignment.RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", KeyVaultBuiltInRole.KeyVaultAdministrator.ToString());
59-
kvMiRoleAssignment.PrincipalId = infrastructure.Identity.PrincipalId;
60-
infrastructure.AddResource(kvMiRoleAssignment);
49+
RequiredSystemRoles.Add(keyVaultResource, [(KeyVaultBuiltInRole.GetBuiltInRoleName(KeyVaultBuiltInRole.KeyVaultAdministrator), KeyVaultBuiltInRole.KeyVaultAdministrator.ToString())]);
6150

6251
return keyVaultResource;
6352
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/AzureSdkExtensions/OpenAIFeature.cs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License.
33
using System;
44
using System.Collections.Generic;
5-
using Azure.Provisioning.Authorization;
65
using Azure.Provisioning.CloudMachine;
76
using Azure.Provisioning.CognitiveServices;
87
using Azure.Provisioning.Primitives;
@@ -14,25 +13,14 @@ internal class OpenAIFeature : CloudMachineFeature
1413
private List<OpenAIModel> _models = new List<OpenAIModel>();
1514

1615
public OpenAIFeature()
17-
{}
16+
{ }
1817

1918
protected override ProvisionableResource EmitCore(CloudMachineInfrastructure cloudMachine)
2019
{
2120
CognitiveServicesAccount cognitiveServices = CreateOpenAIAccount(cloudMachine);
2221
cloudMachine.AddResource(cognitiveServices);
2322

24-
cloudMachine.AddResource(cognitiveServices.CreateRoleAssignment(
25-
CognitiveServicesBuiltInRole.CognitiveServicesOpenAIContributor,
26-
RoleManagementPrincipalType.User,
27-
cloudMachine.PrincipalIdParameter)
28-
);
29-
30-
cloudMachine.AddResource(cloudMachine.CreateRoleAssignment(
31-
cognitiveServices,
32-
cognitiveServices.Id,
33-
CognitiveServicesBuiltInRole.CognitiveServicesOpenAIContributor,
34-
cloudMachine.Identity)
35-
);
23+
RequiredSystemRoles.Add(cognitiveServices, [(CognitiveServicesBuiltInRole.GetBuiltInRoleName(CognitiveServicesBuiltInRole.CognitiveServicesOpenAIContributor) ,CognitiveServicesBuiltInRole.CognitiveServicesOpenAIContributor.ToString())]);
3624

3725
Emitted = cognitiveServices;
3826

@@ -52,7 +40,7 @@ protected override ProvisionableResource EmitCore(CloudMachineInfrastructure clo
5240

5341
internal void AddModel(OpenAIModel model)
5442
{
55-
if (model.Account!= null)
43+
if (model.Account != null)
5644
{
5745
throw new InvalidOperationException("Model already added to an account");
5846
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/AzureSdkExtensions/OpenAIModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Diagnostics;
67
using Azure.Provisioning.CloudMachine;
78
using Azure.Provisioning.CognitiveServices;
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Azure.Provisioning;
7+
using Azure.Provisioning.Authorization;
8+
using Azure.Provisioning.CloudMachine;
9+
using Azure.Provisioning.EventGrid;
10+
using Azure.Provisioning.Expressions;
11+
using Azure.Provisioning.Primitives;
12+
using Azure.Provisioning.Resources;
13+
using Azure.Provisioning.ServiceBus;
14+
using Azure.Provisioning.Storage;
15+
16+
namespace Azure.CloudMachine;
17+
18+
internal class CloudMachineCoreFeature : CloudMachineFeature
19+
{
20+
public CloudMachineCoreFeature()
21+
{ }
22+
protected override ProvisionableResource EmitCore(CloudMachineInfrastructure infrastructure)
23+
{
24+
ManagedServiceIdentity managedServiceIdentity = new()
25+
{
26+
ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned,
27+
UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } }
28+
};
29+
30+
var _storage =
31+
new StorageAccount("cm_storage", StorageAccount.ResourceVersions.V2023_01_01)
32+
{
33+
Kind = StorageKind.StorageV2,
34+
Sku = new StorageSku { Name = StorageSkuName.StandardLrs },
35+
IsHnsEnabled = true,
36+
AllowBlobPublicAccess = false
37+
};
38+
_storage.Identity = managedServiceIdentity;
39+
_storage.Name = infrastructure.Id;
40+
41+
var _blobs = new BlobService("cm_storage_blobs")
42+
{
43+
Parent = _storage,
44+
};
45+
var _container = new BlobContainer("cm_storage_blobs_container", "2023-01-01")
46+
{
47+
Parent = _blobs,
48+
Name = "default"
49+
};
50+
51+
var _serviceBusNamespace = new ServiceBusNamespace("cm_servicebus")
52+
{
53+
Sku = new ServiceBusSku
54+
{
55+
Name = ServiceBusSkuName.Standard,
56+
Tier = ServiceBusSkuTier.Standard
57+
},
58+
Name = infrastructure.Id,
59+
};
60+
var _serviceBusNamespaceAuthorizationRule = new ServiceBusNamespaceAuthorizationRule("cm_servicebus_auth_rule", "2021-11-01")
61+
{
62+
Parent = _serviceBusNamespace,
63+
Rights = [ServiceBusAccessRight.Listen, ServiceBusAccessRight.Send, ServiceBusAccessRight.Manage]
64+
};
65+
var _serviceBusTopic_private = new ServiceBusTopic("cm_servicebus_topic_private", "2021-11-01")
66+
{
67+
Name = "cm_servicebus_topic_private",
68+
Parent = _serviceBusNamespace,
69+
MaxMessageSizeInKilobytes = 256,
70+
DefaultMessageTimeToLive = TimeSpan.FromDays(14),
71+
RequiresDuplicateDetection = false,
72+
EnableBatchedOperations = true,
73+
SupportOrdering = true,
74+
Status = ServiceBusMessagingEntityStatus.Active
75+
};
76+
var _serviceBusSubscription_private = new ServiceBusSubscription(CloudMachineInfrastructure.SB_PRIVATE_SUB, "2021-11-01")
77+
{
78+
Name = CloudMachineInfrastructure.SB_PRIVATE_SUB,
79+
Parent = _serviceBusTopic_private,
80+
IsClientAffine = false,
81+
LockDuration = TimeSpan.FromSeconds(30),
82+
RequiresSession = false,
83+
DefaultMessageTimeToLive = TimeSpan.FromDays(14),
84+
DeadLetteringOnFilterEvaluationExceptions = true,
85+
DeadLetteringOnMessageExpiration = true,
86+
MaxDeliveryCount = 10,
87+
EnableBatchedOperations = true,
88+
Status = ServiceBusMessagingEntityStatus.Active
89+
};
90+
var _serviceBusTopic_default = new ServiceBusTopic("cm_servicebus_topic_default", "2021-11-01")
91+
{
92+
Name = "cm_servicebus_default_topic",
93+
Parent = _serviceBusNamespace,
94+
MaxMessageSizeInKilobytes = 256,
95+
DefaultMessageTimeToLive = TimeSpan.FromDays(14),
96+
RequiresDuplicateDetection = false,
97+
EnableBatchedOperations = true,
98+
SupportOrdering = true,
99+
Status = ServiceBusMessagingEntityStatus.Active
100+
};
101+
var _serviceBusSubscription_default = new ServiceBusSubscription("cm_servicebus_subscription_default", "2021-11-01")
102+
{
103+
Name = "cm_servicebus_subscription_default",
104+
Parent = _serviceBusTopic_default,
105+
IsClientAffine = false,
106+
LockDuration = TimeSpan.FromSeconds(30),
107+
RequiresSession = false,
108+
DefaultMessageTimeToLive = TimeSpan.FromDays(14),
109+
DeadLetteringOnFilterEvaluationExceptions = true,
110+
DeadLetteringOnMessageExpiration = true,
111+
MaxDeliveryCount = 10,
112+
EnableBatchedOperations = true,
113+
Status = ServiceBusMessagingEntityStatus.Active
114+
};
115+
var _eventGridTopic_blobs = new SystemTopic("cm_eventgrid_topic_blob", "2022-06-15")
116+
{
117+
TopicType = "Microsoft.Storage.StorageAccounts",
118+
Source = _storage.Id,
119+
Identity = new()
120+
{
121+
ManagedServiceIdentityType = ManagedServiceIdentityType.UserAssigned,
122+
UserAssignedIdentities = { { BicepFunction.Interpolate($"{infrastructure.Identity.Id}").Compile().ToString(), new UserAssignedIdentityDetails() } }
123+
},
124+
Name = infrastructure.Id
125+
};
126+
var _eventGridSubscription_blobs = new SystemTopicEventSubscription("cm_eventgrid_subscription_blob", "2022-06-15")
127+
{
128+
Name = "cm-eventgrid-subscription-blob",
129+
Parent = _eventGridTopic_blobs,
130+
DeliveryWithResourceIdentity = new DeliveryWithResourceIdentity
131+
{
132+
Identity = new EventSubscriptionIdentity
133+
{
134+
IdentityType = EventSubscriptionIdentityType.UserAssigned,
135+
UserAssignedIdentity = infrastructure.Identity.Id
136+
},
137+
Destination = new ServiceBusTopicEventSubscriptionDestination
138+
{
139+
ResourceId = _serviceBusTopic_private.Id
140+
}
141+
},
142+
Filter = new EventSubscriptionFilter
143+
{
144+
IncludedEventTypes =
145+
[
146+
"Microsoft.Storage.BlobCreated",
147+
"Microsoft.Storage.BlobDeleted",
148+
"Microsoft.Storage.BlobRenamed"
149+
],
150+
IsAdvancedFilteringOnArraysEnabled = true
151+
},
152+
EventDeliverySchema = EventDeliverySchema.EventGridSchema,
153+
RetryPolicy = new EventSubscriptionRetryPolicy
154+
{
155+
MaxDeliveryAttempts = 30,
156+
EventTimeToLiveInMinutes = 1440
157+
}
158+
};
159+
160+
infrastructure.AddResource(infrastructure.PrincipalIdParameter);
161+
infrastructure.AddResource(infrastructure.Identity);
162+
infrastructure.AddResource(_storage);
163+
RequiredSystemRoles.Add(
164+
_storage,
165+
[
166+
(StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageBlobDataContributor),StorageBuiltInRole.StorageBlobDataContributor.ToString()),
167+
(StorageBuiltInRole.GetBuiltInRoleName(StorageBuiltInRole.StorageTableDataContributor), StorageBuiltInRole.StorageTableDataContributor.ToString())
168+
]);
169+
170+
infrastructure.AddResource(_container);
171+
infrastructure.AddResource(_blobs);
172+
infrastructure.AddResource(_serviceBusNamespace);
173+
174+
RequiredSystemRoles.Add(
175+
_serviceBusNamespace,
176+
[
177+
(ServiceBusBuiltInRole.GetBuiltInRoleName(ServiceBusBuiltInRole.AzureServiceBusDataOwner), ServiceBusBuiltInRole.AzureServiceBusDataOwner.ToString()),
178+
]);
179+
180+
var role = ServiceBusBuiltInRole.AzureServiceBusDataSender;
181+
RoleAssignment roleAssignment = new RoleAssignment("cm_servicebus_role");
182+
roleAssignment.Name = BicepFunction.CreateGuid(_serviceBusNamespace.Id, infrastructure.Identity.Id, BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString()));
183+
roleAssignment.Scope = new IdentifierExpression(_serviceBusNamespace.BicepIdentifier);
184+
roleAssignment.PrincipalType = RoleManagementPrincipalType.ServicePrincipal;
185+
roleAssignment.RoleDefinitionId = BicepFunction.GetSubscriptionResourceId("Microsoft.Authorization/roleDefinitions", role.ToString());
186+
roleAssignment.PrincipalId = infrastructure.Identity.PrincipalId;
187+
infrastructure.AddResource(roleAssignment);
188+
189+
// the role assignment must exist before the system topic event subscription is created.
190+
_eventGridSubscription_blobs.DependsOn.Add(roleAssignment);
191+
192+
infrastructure.AddResource(_serviceBusNamespaceAuthorizationRule);
193+
infrastructure.AddResource(_serviceBusTopic_private);
194+
infrastructure.AddResource(_serviceBusTopic_default);
195+
infrastructure.AddResource(_serviceBusSubscription_private);
196+
infrastructure.AddResource(_serviceBusSubscription_default);
197+
infrastructure.AddResource(_eventGridSubscription_blobs);
198+
infrastructure.AddResource(_eventGridTopic_blobs);
199+
200+
// Placeholders for now.
201+
infrastructure.AddResource(new ProvisioningOutput($"storage_name", typeof(string)) { Value = _storage.Name });
202+
infrastructure.AddResource(new ProvisioningOutput($"servicebus_name", typeof(string)) { Value = _serviceBusNamespace.Name });
203+
204+
return _storage;
205+
}
206+
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/CDKLevel3/CloudMachineFeature.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using System.Collections.Generic;
45
using System.ComponentModel;
56
using Azure.CloudMachine;
67
using Azure.Provisioning.Primitives;
@@ -15,7 +16,8 @@ public abstract class CloudMachineFeature
1516
[EditorBrowsable(EditorBrowsableState.Never)]
1617
public void Emit(CloudMachineInfrastructure cm)
1718
{
18-
if (Emitted != null) return;
19+
if (Emitted != null)
20+
return;
1921
ProvisionableResource provisionable = EmitCore(cm);
2022
Emitted = provisionable;
2123
}
@@ -24,4 +26,6 @@ public void Emit(CloudMachineInfrastructure cm)
2426

2527
[EditorBrowsable(EditorBrowsableState.Never)]
2628
public ProvisionableResource Emitted { get; protected set; } = default!;
29+
30+
protected internal Dictionary<Provisionable, (string RoleName, string RoleId)[]> RequiredSystemRoles { get; } = [];
2731
}

0 commit comments

Comments
 (0)