5
5
using Aspire . Hosting . Azure ;
6
6
using Azure . Provisioning ;
7
7
using Azure . Provisioning . Expressions ;
8
+ using Azure . Provisioning . Primitives ;
8
9
using Azure . Provisioning . Sql ;
9
10
10
11
namespace Aspire . Hosting ;
@@ -205,14 +206,6 @@ private static void CreateSqlServer(
205
206
{
206
207
var resource = SqlServer . FromExisting ( identifier ) ;
207
208
resource . Name = name ;
208
- resource . Administrators = new ServerExternalAdministrator ( )
209
- {
210
- AdministratorType = SqlAdministratorType . ActiveDirectory ,
211
- IsAzureADOnlyAuthenticationEnabled = true ,
212
- Sid = principalIdParameter ,
213
- Login = principalNameParameter ,
214
- TenantId = BicepFunction . GetSubscription ( ) . TenantId
215
- } ;
216
209
return resource ;
217
210
} ,
218
211
( infrastructure ) =>
@@ -234,6 +227,20 @@ private static void CreateSqlServer(
234
227
} ;
235
228
} ) ;
236
229
230
+ // If the resource is an existing resource, we model the administrator access
231
+ // for the managed identity as an "edge" between the parent SqlServer resource
232
+ // and a custom SqlServerAzureADAdministrator resource.
233
+ if ( sqlServer . IsExistingResource )
234
+ {
235
+ var admin = new SqlServerAzureADAdministratorWorkaround ( $ "{ sqlServer . BicepIdentifier } _admin")
236
+ {
237
+ ParentOverride = sqlServer ,
238
+ LoginOverride = principalNameParameter ,
239
+ SidOverride = principalIdParameter
240
+ } ;
241
+ infrastructure . Add ( admin ) ;
242
+ }
243
+
237
244
infrastructure . Add ( new SqlFirewallRule ( "sqlFirewallRule_AllowAllAzureIps" )
238
245
{
239
246
Parent = sqlServer ,
@@ -244,11 +251,15 @@ private static void CreateSqlServer(
244
251
245
252
if ( distributedApplicationBuilder . ExecutionContext . IsRunMode )
246
253
{
247
- // When in run mode we inject the users identity and we need to specify
248
- // the principalType.
249
- var principalTypeParameter = new ProvisioningParameter ( AzureBicepResource . KnownParameters . PrincipalType , typeof ( string ) ) ;
250
- infrastructure . Add ( principalTypeParameter ) ;
251
- sqlServer . Administrators . PrincipalType = principalTypeParameter ;
254
+ // Avoid mutating properties on existing resources.
255
+ if ( ! sqlServer . IsExistingResource )
256
+ {
257
+ // When in run mode we inject the users identity and we need to specify
258
+ // the principalType.
259
+ var principalTypeParameter = new ProvisioningParameter ( AzureBicepResource . KnownParameters . PrincipalType , typeof ( string ) ) ;
260
+ infrastructure . Add ( principalTypeParameter ) ;
261
+ sqlServer . Administrators . PrincipalType = principalTypeParameter ;
262
+ }
252
263
253
264
infrastructure . Add ( new SqlFirewallRule ( "sqlFirewallRule_AllowAllIps" )
254
265
{
@@ -273,4 +284,80 @@ private static void CreateSqlServer(
273
284
274
285
infrastructure . Add ( new ProvisioningOutput ( "sqlServerFqdn" , typeof ( string ) ) { Value = sqlServer . FullyQualifiedDomainName } ) ;
275
286
}
287
+
288
+ /// <remarks>
289
+ /// Workaround for issue using SqlServerAzureADAdministrator.
290
+ /// See https://github.com/Azure/azure-sdk-for-net/issues/48364 for more information.
291
+ /// </remarks>
292
+ private sealed class SqlServerAzureADAdministratorWorkaround ( string bicepIdentifier ) : SqlServerAzureADAdministrator ( bicepIdentifier )
293
+ {
294
+ private BicepValue < string > ? _name ;
295
+ private BicepValue < string > ? _login ;
296
+ private BicepValue < Guid > ? _sid ;
297
+ private ResourceReference < SqlServer > ? _parent ;
298
+
299
+ /// <summary>
300
+ /// Login name of the server administrator.
301
+ /// </summary>
302
+ public BicepValue < string > LoginOverride
303
+ {
304
+ get
305
+ {
306
+ Initialize ( ) ;
307
+ return _login ! ;
308
+ }
309
+ set
310
+ {
311
+ Initialize ( ) ;
312
+ _login ! . Assign ( value ) ;
313
+ }
314
+ }
315
+
316
+ /// <summary>
317
+ /// SID (object ID) of the server administrator.
318
+ /// </summary>
319
+ public BicepValue < Guid > SidOverride
320
+ {
321
+ get
322
+ {
323
+ Initialize ( ) ;
324
+ return _sid ! ;
325
+ }
326
+ set
327
+ {
328
+ Initialize ( ) ;
329
+ _sid ! . Assign ( value ) ;
330
+ }
331
+ }
332
+
333
+ /// <summary>
334
+ /// Parent resource of the server administrator.
335
+ /// </summary>
336
+ public SqlServer ? ParentOverride
337
+ {
338
+ get
339
+ {
340
+ Initialize ( ) ;
341
+ return _parent ! . Value ;
342
+ }
343
+ set
344
+ {
345
+ Initialize ( ) ;
346
+ _parent ! . Value = value ;
347
+ }
348
+ }
349
+
350
+ private static BicepValue < string > GetNameDefaultValue ( )
351
+ {
352
+ return new StringLiteralExpression ( "ActiveDirectory" ) ;
353
+ }
354
+
355
+ protected override void DefineProvisionableProperties ( )
356
+ {
357
+ _name = DefineProperty ( "Name" , [ "name" ] , defaultValue : GetNameDefaultValue ( ) ) ;
358
+ _login = DefineProperty < string > ( "Login" , [ "properties" , "login" ] ) ;
359
+ _sid = DefineProperty < Guid > ( "Sid" , [ "properties" , "sid" ] ) ;
360
+ _parent = DefineResource < SqlServer > ( "Parent" , [ "parent" ] , isOutput : false , isRequired : true ) ;
361
+ }
362
+ }
276
363
}
0 commit comments