Skip to content

Commit 84e464f

Browse files
committed
Added demo code to pulumi infra to make users in group a reader
1 parent c2f8141 commit 84e464f

File tree

13 files changed

+270
-24
lines changed

13 files changed

+270
-24
lines changed

update-conference-prague-2024/demo-code-feedback-system/infra/Builders/ApiBuilder.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Pulumi.AzureNative.Web;
1515
using Pulumi.AzureNative.Web.Inputs;
1616

17+
using PulumiInfra.Builders.AzureResourceGroup;
1718
using PulumiInfra.Config;
1819

1920
using AzureNative = Pulumi.AzureNative;
@@ -28,7 +29,7 @@ public record FunctionInfra(WebApp WebApp, Output<string> HttpsEndpoint);
2829

2930
public record ApiBuilder(
3031
GlobalConfig GlobalConfig,
31-
ResourceGroup ResourceGroup,
32+
AzureResourceGroupInfrasatructure ResourceGroupInfra,
3233
PersistentStorageResources PersistenceResources)
3334
{
3435
public ApiResources Build()
@@ -44,7 +45,7 @@ private ApiResources.ServiceStorageInfra GenerateStorageInfrastructure()
4445
{
4546
var storageAccount = new StorageAccount("funcsstorage", new StorageAccountArgs
4647
{
47-
ResourceGroupName = ResourceGroup.Name,
48+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
4849
Sku = new AzureNative.Storage.Inputs.SkuArgs
4950
{
5051
Name = AzureNative.Storage.SkuName.Standard_LRS,
@@ -66,15 +67,15 @@ private ApiResources.ServiceStorageInfra GenerateStorageInfrastructure()
6667
{
6768
AccountName = storageAccount.Name,
6869
PublicAccess = PublicAccess.None,
69-
ResourceGroupName = ResourceGroup.Name,
70+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
7071
});
7172

7273
var functionsBlob = new Blob("functions-blob", new BlobArgs
7374
{
7475
AccountName = storageAccount.Name,
7576
ContainerName = functionsContainer.Name,
7677
AccessTier = BlobAccessTier.Hot,
77-
ResourceGroupName = ResourceGroup.Name,
78+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
7879
Source = new FileArchive(GlobalConfig.ApiConfig.FunctionsPackagePath),
7980
BlobName = "functions.zip",
8081
});
@@ -90,7 +91,7 @@ private ApiResources.FunctionInfra GenerateFunctionsInfrastructure(ApiResources.
9091
//Create the App Service Plan
9192
var appServicePlan = new AppServicePlan("functions-app-service-plan", new AppServicePlanArgs
9293
{
93-
ResourceGroupName = ResourceGroup.Name,
94+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
9495
Kind = "Linux",
9596
Sku = new SkuDescriptionArgs
9697
{
@@ -162,7 +163,7 @@ private ApiResources.FunctionInfra GenerateFunctionsInfrastructure(ApiResources.
162163
var webApp = new WebApp("functions-app", new WebAppArgs
163164
{
164165
Kind = "FunctionApp",
165-
ResourceGroupName = ResourceGroup.Name,
166+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
166167
ServerFarmId = appServicePlan.Id,
167168
HttpsOnly = true,
168169
SiteConfig = functionAppSiteConfig,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Pulumi.AzureAD;
2+
using Pulumi.AzureNative.Resources;
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Collections.Immutable;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
using static PulumiInfra.Builders.AzureResourceGroup.AzureResourceGroupInfrasatructure;
12+
13+
namespace PulumiInfra.Builders.AzureResourceGroup;
14+
15+
public record AzureResourceGroupInfrasatructure(
16+
ResourceGroupInfrastructure ResourceGroupInfra,
17+
AdGroupInfrastructure AdGroupInfra)
18+
{
19+
public record ResourceGroupInfrastructure(ResourceGroup ResourceGroup);
20+
public record AdGroupInfrastructure(Group Group, string GroupName, ImmutableArray<GroupMember> GroupMembers);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using Pulumi;
2+
3+
using System;
4+
using System.Threading.Tasks;
5+
using System.Linq;
6+
7+
using Pulumi.AzureNative.Resources;
8+
9+
10+
using AzureNative = Pulumi.AzureNative;
11+
using static PulumiInfra.Builders.AzureResourceGroup.AzureResourceGroupInfrasatructure;
12+
using System.Collections.Generic;
13+
using System.Collections.Immutable;
14+
using PulumiInfra.Builders.AzureResourceGroup;
15+
using PulumiInfra.Config;
16+
using Pulumi.AzureAD;
17+
using PulumiInfra.Utilities;
18+
19+
public record AzureResourceGroupStackBuilder(
20+
GlobalConfig GlobalConfig)
21+
{
22+
public AzureResourceGroupInfrasatructure GenerateResources()
23+
{
24+
var resourceGroupInfra = GenerateResourceGroup();
25+
var adGroupsInfra = GenerateAdGroup(resourceGroupInfra);
26+
27+
AssignRbacAccess(resourceGroupInfra, adGroupsInfra);
28+
29+
return new AzureResourceGroupInfrasatructure(resourceGroupInfra, adGroupsInfra);
30+
}
31+
32+
private ResourceGroupInfrastructure GenerateResourceGroup()
33+
{
34+
var resourceGroup = new ResourceGroup(GlobalConfig.ApiConfig.ResourceGroupName, new ResourceGroupArgs
35+
{
36+
Location = GlobalConfig.ApiConfig.Location,
37+
Tags = new InputMap<string> {
38+
{ "environment", GlobalConfig.ServiceConfig.Environment },
39+
{ "service-version", GlobalConfig.ServiceConfig.Version }
40+
}
41+
});
42+
43+
return new ResourceGroupInfrastructure(resourceGroup);
44+
}
45+
46+
private AdGroupInfrastructure GenerateAdGroup(ResourceGroupInfrastructure resourceGroupInfra)
47+
{
48+
var group = new Group(GlobalConfig.ResourceUsersConfig.GroupName, new GroupArgs
49+
{
50+
DisplayName = GlobalConfig.ResourceUsersConfig.GroupName,
51+
Description = resourceGroupInfra.ResourceGroup.Name.Apply(x => $"Users with access to resources in Resource Group {x}. Generally have access to 'read' the resources, but sometimes the ability to also 'write'."),
52+
SecurityEnabled = true,
53+
PreventDuplicateNames = true,
54+
});
55+
56+
var groupMembers = new List<GroupMember>();
57+
foreach (var user in GlobalConfig.ResourceUsersConfig.Users)
58+
{
59+
var sanitizedUserName = user.DisplayName.Replace(" ", "-");
60+
var memberName = $"{GlobalConfig.ResourceUsersConfig.GroupName}-{sanitizedUserName}";
61+
62+
var groupMember = new GroupMember(memberName, new()
63+
{
64+
GroupObjectId = group.Id,
65+
MemberObjectId = user.ObjectId
66+
});
67+
68+
groupMembers.Add(groupMember);
69+
}
70+
71+
return new AdGroupInfrastructure(group, GlobalConfig.ResourceUsersConfig.GroupName, groupMembers.ToImmutableArray());
72+
}
73+
74+
private void AssignRbacAccess(ResourceGroupInfrastructure resourceGroupInfra, AdGroupInfrastructure adGroupsInfra)
75+
{
76+
//Assign group to be able to read everything in the resource group
77+
_ = new AzureNative.Authorization.RoleAssignment("arcade-device-management-resource-group-reader-role-assignment", new AzureNative.Authorization.RoleAssignmentArgs
78+
{
79+
PrincipalId = adGroupsInfra.Group.Id,
80+
PrincipalType = AzureNative.Authorization.PrincipalType.Group,
81+
RoleDefinitionId = AzureAdRoleIdUtilities.GenerateAzureReaderRoleId(GlobalConfig.ApiConfig.ClientConfig.SubscriptionId),
82+
Scope = resourceGroupInfra.ResourceGroup.Id
83+
});
84+
}
85+
}

update-conference-prague-2024/demo-code-feedback-system/infra/Builders/PersistentStorageBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Pulumi.AzureNative.Resources;
1414
using Pulumi.AzureNative.Storage;
1515

16+
using PulumiInfra.Builders.AzureResourceGroup;
1617
using PulumiInfra.Config;
1718

1819
using AzureNative = Pulumi.AzureNative;
@@ -26,7 +27,7 @@ public record PersistentStorageInfra(StorageAccount StorageAccount);
2627

2728
public record PersistentStorageBuilder(
2829
GlobalConfig GlobalConfig,
29-
ResourceGroup ResourceGroup)
30+
AzureResourceGroupInfrasatructure ResourceGroupInfra)
3031
{
3132
public PersistentStorageResources Build()
3233
{
@@ -38,7 +39,7 @@ private PersistentStorageResources.PersistentStorageInfra GenerateStorageInfrast
3839
{
3940
var storageAccount = new StorageAccount("persistentstg", new StorageAccountArgs
4041
{
41-
ResourceGroupName = ResourceGroup.Name,
42+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
4243
Sku = new AzureNative.Storage.Inputs.SkuArgs
4344
{
4445
Name = AzureNative.Storage.SkuName.Standard_LRS,

update-conference-prague-2024/demo-code-feedback-system/infra/Builders/StaticSiteBuilder.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Pulumi.AzureNative.Web;
1717
using Pulumi.AzureNative.Web.Inputs;
1818

19+
using PulumiInfra.Builders.AzureResourceGroup;
1920
using PulumiInfra.Config;
2021
using PulumiInfra.Utilities;
2122

@@ -32,7 +33,7 @@ public record SiteStorageInfra(StorageAccount SiteStorageAccount, StorageAccount
3233

3334
public record StaticSiteBuilder(
3435
GlobalConfig GlobalConfig,
35-
ResourceGroup ResourceGroup,
36+
AzureResourceGroupInfrasatructure ResourceGroupInfra,
3637
ApiResources ApiResources)
3738
{
3839
public StaticSiteResources Build()
@@ -45,7 +46,7 @@ private SiteStorageInfra GenerateSiteInfra()
4546
{
4647
var storageAccount = new StorageAccount("sitestorage", new StorageAccountArgs
4748
{
48-
ResourceGroupName = ResourceGroup.Name,
49+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
4950
AllowBlobPublicAccess = true,
5051
Sku = new AzureNative.Storage.Inputs.SkuArgs
5152
{
@@ -65,7 +66,7 @@ private SiteStorageInfra GenerateSiteInfra()
6566

6667
var siteStorageAccount = new StorageAccountStaticWebsite("staticsiteaccount", new StorageAccountStaticWebsiteArgs
6768
{
68-
ResourceGroupName = ResourceGroup.Name,
69+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
6970
IndexDocument = "index.html",
7071
Error404Document = "index.html",
7172
AccountName = storageAccount.Name
@@ -88,7 +89,7 @@ private SiteStorageInfra GenerateSiteInfra()
8889
AccountName = storageAccount.Name,
8990
ContainerName = "$web",
9091
AccessTier = BlobAccessTier.Hot,
91-
ResourceGroupName = ResourceGroup.Name,
92+
ResourceGroupName = ResourceGroupInfra.ResourceGroupInfra.ResourceGroup.Name,
9293
Source = new FileAsset(fullFilePath),
9394
ContentType = FileUtilities.DetermineFileContentType(fullFilePath),
9495
BlobName = relativeFilePath,

update-conference-prague-2024/demo-code-feedback-system/infra/Config/GlobalConfig.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ namespace PulumiInfra.Config;
1212
public record GlobalConfig(
1313
ServiceConfig ServiceConfig,
1414
ApiConfig ApiConfig,
15-
StaticSiteConfig StaticSiteConfig
15+
StaticSiteConfig StaticSiteConfig,
16+
ResourceUsersConfig ResourceUsersConfig
1617
)
1718
{
1819
public static async Task<GlobalConfig> LoadAsync(Pulumi.Config config)
@@ -35,7 +36,8 @@ public static async Task<GlobalConfig> LoadAsync(Pulumi.Config config)
3536
return new GlobalConfig(
3637
ServiceConfig: config.RequireObject<ServiceConfigDto>("service-config").GenerateValidConfigObject(),
3738
ApiConfig: apiConfig.GenerateValidConfigObject(),
38-
StaticSiteConfig: staticSiteConfig.GenerateValidConfigObject()
39+
StaticSiteConfig: staticSiteConfig.GenerateValidConfigObject(),
40+
ResourceUsersConfig: config.RequireObject<ResourceUsersConfigDto>("resource-users-config").GenerateValidConfigObject()
3941
);
4042
}
4143
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Pulumi.AzureAD.Outputs;
2+
3+
using PulumiInfra.Utilities;
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Diagnostics.CodeAnalysis;
9+
using System.Linq;
10+
using System.Text;
11+
using System.Threading.Tasks;
12+
13+
namespace PulumiInfra.Config;
14+
public record ResourceUsersConfig(
15+
string GroupName,
16+
ImmutableArray<GetUsersUserResult> Users);
17+
18+
public class ResourceUsersConfigDto : ConfigDtoBase<ResourceUsersConfig>
19+
{
20+
public string? GroupName { get; set; }
21+
public string?[]? Users { get; set; }
22+
23+
public override ResourceUsersConfig GenerateValidConfigObject()
24+
{
25+
if (!string.IsNullOrWhiteSpace(GroupName)
26+
&& Users != null && Users.All(x => !string.IsNullOrWhiteSpace(x)))
27+
{
28+
var userEmails = Users.ToImmutableArray();
29+
var users = AzureUtilities.LoadUsersFromAzureAd(userEmails);
30+
31+
return new(GroupName, users);
32+
}
33+
34+
throw new Exception($"{GetType().Name} has invalid config");
35+
}
36+
}

update-conference-prague-2024/demo-code-feedback-system/infra/Program.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@
1212
var pulumiConfig = new Config();
1313
var globalConfig = await GlobalConfig.LoadAsync(pulumiConfig);
1414

15-
var resourceGroup = new ResourceGroup(globalConfig.ApiConfig.ResourceGroupName, new ResourceGroupArgs
16-
{
17-
Location = globalConfig.ApiConfig.Location
18-
});
15+
var resourceGroupBuilder = new AzureResourceGroupStackBuilder(globalConfig);
16+
var resourceGroupResources = resourceGroupBuilder.GenerateResources();
1917

20-
var persistentStorageBuilder = new PersistentStorageBuilder(globalConfig, resourceGroup);
18+
var persistentStorageBuilder = new PersistentStorageBuilder(globalConfig, resourceGroupResources);
2119
var persistenceResources = persistentStorageBuilder.Build();
2220

23-
var apiBuilder = new ApiBuilder(globalConfig, resourceGroup, persistenceResources);
21+
var apiBuilder = new ApiBuilder(globalConfig, resourceGroupResources, persistenceResources);
2422
var apiResources = apiBuilder.Build();
2523

26-
var staticSiteBuilder = new StaticSiteBuilder(globalConfig, resourceGroup, apiResources);
24+
var staticSiteBuilder = new StaticSiteBuilder(globalConfig, resourceGroupResources, apiResources);
2725
var staticSiteResources = staticSiteBuilder.Build();
2826

2927
return new Dictionary<string, object?>

update-conference-prague-2024/demo-code-feedback-system/infra/Pulumi.dev.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ config:
66
update-conf-2024:service-config:
77
Version: dev-version-123
88
Environment: dev
9-
pulumi:template: azure-csharp
9+
update-conf-2024:resource-users-config:
10+
GroupName: dev-users
11+
Users:
12+
13+
pulumi:template: azure-csharp

update-conference-prague-2024/demo-code-feedback-system/infra/PulumiInfra.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<LangVersion>latest</LangVersion><EnableNETAnalyzers>true</EnableNETAnalyzers><EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild></PropertyGroup>
99

1010
<ItemGroup>
11+
<PackageReference Include="Pulumi.AzureAD" Version="6.0.1" />
1112
<PackageReference Include="Pulumi" Version="3.67.1" />
1213
<PackageReference Include="Pulumi.AzureNative" Version="2.64.3" />
1314
</ItemGroup>

0 commit comments

Comments
 (0)