-
Notifications
You must be signed in to change notification settings - Fork 83
/
Copy pathCreate_SP.ps1
428 lines (386 loc) · 13.8 KB
/
Create_SP.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
<#
.SYNOPSIS
Generate or Delete an Azure Application needed for goose usage
.DESCRIPTION
Generate or Delete an Azure Application needed for goose usage
Utilizes Microsoft Graph Powershell SDK, Azure SDK, and ExchangeManagementOnline
.EXAMPLE
Write-Host "Creating a new Goose Application"
PS > ./Create_SP.ps1 -AppName GooseApp -Create
.EXAMPLE
Write-Host "Deleting a previously created Goose Application"
PS > ./Create_SP.ps1 -AppName GooseApp -Delete
#>
[cmdletbinding()]Param(
[string] $AppName # Display Name for the Application
,[switch] $Create=$False # Boolean flag on whether to create. Will prompt if not defined. If both Create and Delete are defined then will prompt
,[switch] $Delete=$False # Boolean flag on whether to delete. Will prompt if not defined. If both Create and Delete are defined then will prompt
,[switch] $Force=$False # Boolean flag on whether to Force deletion or creation without prompting
,[switch] $NoSubscriptions=$False # Boolean flag on whether to not apply subscription level roles
,[switch] $GccHigh=$False # Boolean flag on whether to set it up for a Gcc High Environment
)
$script:UserNames = @()
$script:UserSecrets = @()
$script:OutputSubscriptionId = @()
$permissions = @{
"Log Analytics API" = @(
"Data.Read"
)
"Microsoft Threat Protection" = @(
"AdvancedHunting.Read.All"
)
"WindowsDefenderATP" = @(
"AdvancedQuery.Read.All",
"Alert.Read.All",
"Library.Manage",
"Machine.Read.All",
"SecurityRecommendation.Read.All",
"Software.Read.All",
"Ti.ReadWrite",
"Vulnerability.Read.All"
)
"Office 365 Exchange Online" = @(
"Exchange.ManageAsApp"
)
"Microsoft Graph" = @(
"AdministrativeUnit.Read.All",
"APIConnectors.Read.All",
"AuditLog.Read.All",
"ConsentRequest.Read.All",
"Directory.Read.All",
"Domain.Read.All",
"ExternalUserProfile.Read.All",
"Group.Read.All",
"IdentityProvider.Read.All",
"IdentityRiskEvent.Read.All",
"IdentityRiskyServicePrincipal.Read.All",
"IdentityRiskyUser.Read.All",
"MailboxSettings.Read",
"PendingExternalUserProfile.Read.All",
"Policy.Read.All",
"Policy.Read.PermissionGrant",
"Reports.Read.All",
"ResourceSpecificPermissionGrant.ReadForUser.All",
"RoleManagement.Read.All",
"SecurityActions.Read.All",
"SecurityAlert.Read.All",
"SecurityEvents.Read.All",
"Team.ReadBasic.All",
"TeamsAppInstallation.ReadForUser.All",
"ThreatHunting.Read.All",
"User.Read.All",
"UserAuthenticationMethod.Read.All"
)
}
$app_roles = @(
"Reader",
"Storage Blob Data Reader",
"Storage Queue Data Reader"
)
$user_roles = @(
"Reader"
)
$exchange_roles = @(
"View-Only Audit Logs",
"View-Only Configuration",
"View-Only Recipients",
"User Options"
)
Function Install-Single-Module {
param(
[string] $ModuleName,
[string] $Version
)
# Download the module if it doesn't exist
If (-not (Get-Module -Name $ModuleName -ListAvailable)) {
Write-Host "Installing $ModuleName from default repository"
Install-Module -Name $ModuleName -RequiredVersion $Version -Force -AllowClobber
}
# Import it if not currently installed
If ($null -eq (Get-InstalledModule $ModuleName -RequiredVersion $Version)) {
Write-Host "Importing $ModuleName"
Import-Module -Name $ModuleNAme -RequiredVersion $AzVersion -Force
}
}
# Install the required modules if not already installed
Function Install-Modules {
Write-Host "Starting package installation. This part can take a few minutes"
$GraphVersion = 2.25.0
$AzVersion = 7.8.0
$ExchangeOnlineVersion = 3.7.0
Install-Single-Module -ModuleName "Az.Resources" -Version $AzVersion
Install-Single-Module -ModuleName "Microsoft.Graph.Applications" -Version $GraphVersion
Install-Single-Module -ModuleName "ExchangeOnlineManagement" -Version $ExchangeOnlineVersion
}
Function Delete-GooseApp {
param(
[string] $AppName,
[bool] $Force=$false
)
# Query Microsoft Graph to find the service principal by display name
$ServicePrincipals = Get-MgServicePrincipal -Filter "displayName eq '$AppName'"
if ($Force -eq $false) {
$Delete = Read-Host "Are you sure you want to delete the application '$AppName'? Y/N"
Switch ($Create){
Y {$Delete = $true}
N {$Delete = $false}
}
if ($Delete -eq $false) {
Write-Host "Stopping Deletion"
Return
}
}
If ($ServicePrincipals) {
foreach ($ServicePrincipal in $ServicePrincipals)
{
# Role assignments need to be removed. Otherwise will leave empty role assignments on the subscriptions
Write-Host "Removing Roles $app_roles"
$Subscriptions = Get-AzSubscription
foreach ($Subscription in $Subscriptions) {
$SubscriptionName = ($Subscription | Select-Object -ExpandProperty Name)
Write-Host "Removing Roles from Subscription '$SubscriptionName'"
foreach ($role in $app_roles) {
$SubscriptionId = ($Subscription | Select-Object -ExpandProperty Id)
Remove-AzRoleAssignment -ObjectId $ServicePrincipal.Id -Scope "/subscriptions/$SubscriptionId" -RoleDefinitionName $role
Write-Host "Removed role $role from service principal."
}
}
# Delete the service principal
Remove-MgServicePrincipal -ServicePrincipalId $ServicePrincipal.Id
Write-Host "Service Principal '$AppName' Deleted"
}
} Else {
Write-Host "Service Principal with the name '$AppName' not found."
}
$Applications = Get-MgApplication -Filter "displayName eq '$AppName'"
If ($Applications) {
foreach ($Application in $Applications)
{
# Delete the Application
Remove-MgApplication -ApplicationId $Application.Id
Write-Host "Application '$AppName' Deleted"
}
} Else {
Write-Host "Application with the name '$AppName' not found."
}
}
Function Create-GooseApp{
param(
[string] $AppName,
[array] $SubscriptionsUsed
)
# Define the required permissions
$displayName = $AppName
# Create a new Entra ID App Registration for the service principal
$newAppRegistration = Get-MgApplication -Filter "displayName eq '$AppName'"
if (-not $newAppRegistration) {
Write-Host "Application '$AppName' does not exist. Creating now"
New-MgApplication -DisplayName $displayName
}
$newAppRegistration = Get-MgApplication -Filter "displayName eq '$AppName'"
# Create a service principal for the new app registration
$ServicePrincipal = Get-MgServicePrincipal -Filter "displayName eq '$displayName'"
if (-not $ServicePrincipal) {
Write-Host "Service Principal for '$AppName' does not exist. Creating now"
New-MgServicePrincipal -AppId $newAppRegistration.AppId
}
$ServicePrincipal = Get-MgServicePrincipal -Filter "displayName eq '$displayName'"
# Get the object ID of the new service principal
$ServicePrincipalId = $ServicePrincipal.Id
# Iterate through the permissions and add them to the service principal
foreach ($scope in $permissions.Keys) {
Write-Host "Adding permissions for scope $scope"
$ResourceApplication = Get-MgServicePrincipal -Filter "displayName eq '$scope'"
foreach ($permission in $permissions[$scope]) {
Write-Host "Assigning permission $permission from $scope to $AppName"
$AppRoleId = ($ResourceApplication.appRoles | where value -eq $permission).Id
$ResourceId = $ResourceApplication.Id
$exists = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $servicePrincipalId | where appRoleId -eq $AppRoleId
If ($exists) {
Write-Host "Permission $permission already in service principal"
}
Else {
$params = @{
principalId = $ServicePrincipalId
resourceId = $ResourceId
appRoleId = $AppRoleId
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipalId -BodyParameter $params
Write-Host "Permission $permission added to service principal"
}
}
}
# Subscription IAM Roles
Write-Host "Assigning Roles $app_roles"
# Assign the roles to the service principal
$Subscriptions = Get-AzSubscription
foreach ($Subscription in $Subscriptions) {
$SubscriptionId = ($Subscription | Select-Object -ExpandProperty Id)
if ($SubscriptionsUsed -contains "all" -or $SubscriptionsUsed -contains $SubscriptionId) {
foreach ($role in $app_roles) {
if ($ServicePrincipal -ne $null) {
New-AzRoleAssignment -ApplicationId $ServicePrincipal.AppId -Scope "/subscriptions/$SubscriptionId" -RoleDefinitionName $role
Write-Host "Assigned role $role to service principal."
}
}
}
}
$AppId = $newAppRegistration.AppId
Return $AppId, $ServicePrincipalId
}
Function Delete-ExchangeServicePrincipal {
param(
[string] $AppName,
[bool] $Force=$false
)
# Get the AppId
$AppId = (Get-MgApplication -Filter "displayName eq '$AppName'").AppId
# Get the Service Principal Id
$ObjectId = (Get-MgServicePrincipal -Filter "displayName eq '$AppName'").Id
# Remove the role group and service principal created for goose
if ($Force) {
Remove-RoleGroupMember -Identity "$AppName" -Member $ObjectId -Confirm:$false
Remove-ServicePrincipal -Identity $ObjectId -Confirm:$false
Remove-RoleGroup "$AppName" -Confirm:$false
}
Else {
Remove-RoleGroupMember -Identity "$AppName" -Member $ObjectId
Remove-ServicePrincipal -Identity $ObjectId
Remove-RoleGroup "$AppName"
}
}
Function Create-ExchangeServicePrincipal {
param(
[string] $AppName
)
# Create the Exchange Online group and add permissions needed
$RoleGroup = $false
$ServicePrincipal = $false
$RoleGroupMember = $false
# Get the AppId
$AppId = (Get-MgApplication -Filter "displayName eq '$AppName'").AppId
# Get the Service Principal Id
$ObjectId = (Get-MgServicePrincipal -Filter "displayName eq '$AppName'").Id
$RoleGroup = Get-RoleGroup $AppName
if (-not $RoleGroup) {
$RoleGroup = New-RoleGroup -Name $AppName -Roles $exchange_roles
}
if ($RoleGroup) {
Write-Host "Role Group '$AppName' created or exists"
# Associate the Exchange Online service principal with the new service principal
$ServicePrincipal = New-ServicePrincipal -AppId $AppId -ObjectId $ObjectId -DisplayName $AppName
}
if ($ServicePrincipal) {
Write-Host "Exchange Service Principal '$AppName' created"
$RoleGroupMember = Add-RoleGroupMember -Identity $AppName -Member $ObjectId
}
if ($RoleGroupMember) {
Write-Host "Role Group '$AppName' created"
}
}
Function Choose-Subscriptions {
param(
[bool] $Force=$false
,[bool] $NoSubscriptions=$false
)
$Subscriptions = Get-AzSubscription
$SubscriptionIds = @()
$AllSubscriptions = $true
$SubscriptionsUsed = ""
if ($NoSubscriptions) {
return $SubscriptionsUsed
}
foreach ($Subscription in $Subscriptions) {
$SubscriptionName = ($Subscription | Select-Object -ExpandProperty Name)
If ($Force -eq $true) {
$CreateRoles = "Y"
}
Else {
$CreateRoles = Read-Host "Assign user/app roles for subscription '$SubscriptionName'? Y/N"
}
Switch ($CreateRoles){
Y {$CreateRoles = $true}
N {$CreateRoles = $false}
}
if ($CreateRoles) {
$SubscriptionsUsed += ($Subscription | Select-Object -ExpandProperty Id)
}
else {
$AllSubscriptions = $false
}
}
if ($AllSubscriptions) {
$SubscriptionsUsed = @("all")
}
else {
$SubscriptionsUsed = $SubscriptionIds
}
return $SubscriptionsUsed
}
Function Output-Results {
param(
[string] $AppId,
[string] $TenantId,
[string] $ClientSecret,
[string] $SubscriptionsUsed
)
$SubscriptionIds = $SubscriptionsUsed -join ","
# Make sure this part contrasts
Write-Host -ForegroundColor Green -BackgroundColor Black "Use the below output to generate the UGT configuration"
Write-Host -ForegroundColor DarkGreen -BackgroundColor Black "goosey conf --config_tenant=$TenantId --config_subscriptionid=$SubscriptionIds --auth_appid=$AppId"
Write-Host -ForegroundColor Green -BackgroundColor Black "Enter the below client secret when prompted during the goosey conf command"
Write-Host -ForegroundColor DarkGreen -BackgroundColor Black "Client Secret: $ClientSecret"
}
if (-not $AppName) {
$AppName = Read-Host "Enter the application name"
}
if (($Create -eq $false -and $Delete -eq $false) -or ($Create -eq $true -and $Delete -eq $true)) {
$Create_read = Read-Host 'Do you want to create or delete a goose app and users? C/D'
Switch ($Create_read){
C {$Create = $true}
D {$Create = $false}
}
}
Install-Modules
$AzEnvironment = "AzureCloud"
$GraphEnvironment = "Global"
$ExchangeEnvironment = "O365Default"
if ($GccHigh) {
$AzEnvironment = "AzureUSGovernment"
$GraphEnvironment = "USGov"
$ExchangeEnvironment = "O365USGovGCCHigh"
}
Connect-AzAccount -WarningVariable ConnectAzOutput -Environment $AzEnvironment
Write-Host $ConnectAzOutput
if ($ConnectAzOutput -Match "Interactive authentication is not supported") {
Write-Host "here"
Connect-AzAccount -UseDeviceAuthentication -Environment $AzEnvironment
}
Connect-MgGraph -Scope 'Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All,Directory.ReadWrite.All' -NoWelcome -Environment $GraphEnvironment
Connect-ExchangeOnline -ShowBanner:$false -ExchangeEnvironmentName $ExchangeEnvironment
If ($Create) {
$SubscriptionsUsed = Choose-Subscriptions -Force $Force -NoSubscriptions $NoSubscriptions
$AppId, $ObjectId = Create-GooseApp -AppName $AppName -SubscriptionsUsed $SubscriptionsUsed
Create-ExchangeServicePrincipal -AppId $AppId -AppName $AppName -ObjectId $ObjectId
# Generate secret and grab details needed for goosey conf
$TenantId = (Get-AzTenant).Id
$AppId = (Get-MgApplication -Filter "displayName eq '$AppName'").AppId
$ServicePrincipalId = (Get-MgServicePrincipal -Filter "displayName eq '$AppName'").Id
$params = @{
passwordCredential = @{
displayName = "$AppName secret"
}
}
$ClientSecret = (Add-MgServicePrincipalPassword -ServicePrincipalId $ServicePrincipalId -BodyParameter $params).SecretText
Disconnect-AzAccount
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph
Output-Results -TenantId $TenantId -AppId $AppId -SubscriptionsUsed $SubscriptionsUsed -ClientSecret $ClientSecret
}
Else {
Delete-ExchangeServicePrincipal -AppName $AppName -Force $Force
Delete-GooseApp -AppName $AppName -Force $Force
Disconnect-AzAccount
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph
}