-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add managed identities support to RG setup scripts #837
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -29,23 +29,42 @@ The *control plane RG* is a container for the *persistent* resources of MLOS (re | |||||
|
||||||
```shell | ||||||
# With Powershell, recommended to use Powershell 7 | ||||||
# If provisioning results DB include '-resultsDbArmsParamsFile', otherwise omit | ||||||
|
||||||
# If setting up with a Service Principal | ||||||
./setup-rg.ps1 ` | ||||||
-controlPlaneArmParamsFile $controlPlaneArmParamsFile ` | ||||||
-resultsDbArmParamsFile $resultsDbArmParamsFile # If provisioning results DB, otherwise omit ` | ||||||
-servicePrincipalName $servicePrincipalName ` | ||||||
-resourceGroupName $resourceGroupName ` | ||||||
-resultsDbArmParamsFile $resultsDbArmParamsFile ` | ||||||
-servicePrincipalName $servicePrincipalName ` | ||||||
-certName $certName | ||||||
|
||||||
# If setting up with a Managed Identity | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you give more context in the README about this part? |
||||||
./setup-rg.ps1 ` | ||||||
-controlPlaneArmParamsFile $controlPlaneArmParamsFile ` | ||||||
-resourceGroupName $resourceGroupName ` | ||||||
-resultsDbArmParamsFile $resultsDbArmParamsFile ` | ||||||
-managedIdentityname $managedIdentityName | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
consistent camelCasing please |
||||||
``` | ||||||
|
||||||
```sh | ||||||
# With bash | ||||||
# If provisioning results DB include '--resultsDbArmsParamsFile', otherwise omit | ||||||
|
||||||
# If setting up with a Service Principal | ||||||
./setup-rg.sh \ | ||||||
--controlPlaneArmParamsFile $controlPlaneArmParamsFile \ | ||||||
--resourceGroupName $resourceGroupName \ | ||||||
--resultsDbArmParamsFile $resultsDbArmParamsFile \ | ||||||
--servicePrincipalName $servicePrincipalName \ | ||||||
--resourceGroupName $resourceGroupName \ | ||||||
--certName $certName | ||||||
|
||||||
# If setting up with a Managed Identity | ||||||
./setup-rg.sh \ | ||||||
--controlPlaneArmParamsFile $controlPlaneArmParamsFile \ | ||||||
--resourceGroupName $resourceGroupName \ | ||||||
--resultsDbArmParamsFile $resultsDbArmParamsFile \ | ||||||
--managedIdentityname $managedIdentityName | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
``` | ||||||
|
||||||
where `$*ArmParamsFile` can be the corresponding `*.parameters.json` and from before. However, it also follows the same usage as `--parameters` in [az deployment group create](https://learn.microsoft.com/en-us/cli/azure/deployment/group?view=azure-cli-latest#az-deployment-group-create-examples). | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,14 +11,17 @@ param( | |
# Results DB ARM template params | ||
[Parameter(Mandatory=$False)] | ||
[string] $resultsDbArmParamsFile, | ||
# Other params | ||
[Parameter(Mandatory=$True)] | ||
[string] $servicePrincipalName, | ||
[Parameter(Mandatory=$True)] | ||
[string] $resourceGroupName, | ||
[Parameter(Mandatory=$True)] | ||
# Managed Identity params | ||
[Parameter(Mandatory=$True, ParameterSetName="ByMI")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are using ServicePrincipals and ManagedIdentity mutually exclusive? |
||
[string] $managedIdentityName, | ||
# Service Principal params | ||
[Parameter(Mandatory=$True, ParameterSetName="BySP")] | ||
[string] $servicePrincipalName, | ||
[Parameter(Mandatory=$True, ParameterSetName="BySP")] | ||
[string] $certName, | ||
[Parameter(Mandatory=$False)] | ||
[Parameter(Mandatory=$False, ParameterSetName="BySP")] | ||
[int] $certExpirationYears = 1 | ||
) | ||
|
||
|
@@ -36,6 +39,9 @@ if (!$?) { | |
return | ||
} | ||
|
||
$vmName = $deploymentResults.properties.outputs.vmName.value | ||
$storageAccountNames = $deploymentResults.properties.outputs.storageAccountNames.value | ||
|
||
# Conditional provisioning of results DB | ||
if ($resultsDbArmParamsFile) { | ||
Write-Output "Provisioning results DB..." | ||
|
@@ -51,7 +57,6 @@ if ($resultsDbArmParamsFile) { | |
} | ||
else { | ||
$dbName = $dbDeploymentResults.properties.outputs.dbName.value | ||
$vmName = $deploymentResults.properties.outputs.vmName.value | ||
$vmIpAddress = $deploymentResults.properties.outputs.vmIpAddress.value | ||
|
||
# VM IP access for results DB | ||
|
@@ -83,41 +88,77 @@ $certThumbprint = az keyvault certificate show ` | |
2>$null ` | ||
|| "NOCERT" | ||
|
||
if ($certThumbprint == "NOCERT") { | ||
# The cert does not exist yet. | ||
# Create the service principal if doesn't exist, storing the cert in the keyvault | ||
# If it does exist, this also patches the current service principal with the role | ||
az ad sp create-for-rbac ` | ||
--name $servicePrincipalName ` | ||
--role "Contributor" ` | ||
--scopes $resourceGroupId ` | ||
--create-cert ` | ||
--cert $certName ` | ||
--keyvault $kvName ` | ||
--years $certExpirationYears | ||
} else { | ||
# The cert already exists in the keyvault. | ||
|
||
# Ensure the SP exists with correct roles, without creating a cert. | ||
az ad sp create-for-rbac ` | ||
--name $servicePrincipalName ` | ||
--role "Contributor" ` | ||
--scopes $resourceGroupId ` | ||
|
||
# SP's certs, which are stored in the registered application instead | ||
$servicePrincipalAppId = az ad sp list ` | ||
--display-name $servicePrincipalName ` | ||
--query "[?servicePrincipalType == 'Application'].appId" ` | ||
--output tsv | ||
$spCertThumbprints = az ad app credential list ` | ||
--id $servicePrincipalAppId ` | ||
--cert ` | ||
--query "[].customKeyIdentifier" ` | ||
--output tsv | ||
|
||
if ($spCertThumbprints.Contains($certThumbprint)) { | ||
Write-Output "Keyvault contains the certificate '$certName' that is linked to the service principal '$servicePrincipalName' already." | ||
} else { | ||
Write-Warning "Keyvault already contains a certificate called '$certName', but is not linked with the service principal '$servicePrincipalName'! Skipping cert handling" | ||
switch ($PSCmdlet.ParameterSetName) { | ||
"BySP" { | ||
if ($certThumbprint -eq "NOCERT") { | ||
# The cert does not exist yet. | ||
# Create the service principal if doesn't exist, storing the cert in the keyvault | ||
# If it does exist, this also patches the current service principal with the role | ||
az ad sp create-for-rbac ` | ||
--name $servicePrincipalName ` | ||
--role "Contributor" ` | ||
--scopes $resourceGroupId ` | ||
--create-cert ` | ||
--cert $certName ` | ||
--keyvault $kvName ` | ||
--years $certExpirationYears | ||
} else { | ||
# The cert already exists in the keyvault. | ||
|
||
# Ensure the SP exists with correct roles, without creating a cert. | ||
az ad sp create-for-rbac ` | ||
--name $servicePrincipalName ` | ||
--role "Contributor" ` | ||
--scopes $resourceGroupId ` | ||
|
||
# SP's certs, which are stored in the registered application instead | ||
$servicePrincipalAppId = az ad sp list ` | ||
--display-name $servicePrincipalName ` | ||
--query "[?servicePrincipalType == 'Application'].appId" ` | ||
--output tsv | ||
$spCertThumbprints = az ad app credential list ` | ||
--id $servicePrincipalAppId ` | ||
--cert ` | ||
--query "[].customKeyIdentifier" ` | ||
--output tsv | ||
|
||
if ($spCertThumbprints.Contains($certThumbprint)) { | ||
Write-Output "Keyvault contains the certificate '$certName' that is linked to the service principal '$servicePrincipalName' already." | ||
} else { | ||
Write-Warning "Keyvault already contains a certificate called '$certName', but is not linked with the service principal '$servicePrincipalName'! Skipping cert handling" | ||
} | ||
} | ||
break | ||
} | ||
"ByMI" { | ||
# Ensure the user managed identity is created | ||
$miId = az identity create ` | ||
--name $managedIdentityName ` | ||
--resource-group $resourceGroupName ` | ||
--query "principalId" --output tsv | ||
|
||
Write-Output "Using managed identity $managedIdentityName with principalId $miId" | ||
|
||
Write-Output "Assigning the identity access to the Resource Group..." | ||
az role assignment create ` | ||
--assignee $miId ` | ||
--role "Contributor" ` | ||
--scope $resourceGroupId | ||
|
||
# Assign the identity to the VM | ||
Write-Output "Assigning the identity to the VM..." | ||
az vm identity assign --name $vmName --resource-group $resourceGroupName --identities $managedIdentityName | ||
|
||
# Assign the identity access to the storage accounts | ||
foreach ($storageAccountName in $storageAccountNames) { | ||
Write-Output "Assigning the identity the role for $storageAccountName..." | ||
$storageAccountResourceId = az storage account show --name $storageAccountName --resource-group $resourceGroupName --query "id" --output tsv | ||
az role assignment create ` | ||
--assignee $miId ` | ||
--role "Storage File Data Privileged Contributor" ` | ||
--scope $storageAccountResourceId | ||
} | ||
break | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has any of this been developed with an eye towards rectifying an existing setup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bpkroth that is a good point. Unfortunately I have only tested this with setting up from scratch.
However, in theory I think this should work for existing resource groups.
Assuming the existing RG was set up with these scripts, I think all the az cli calls (need to confirm) are idempotent.
For example, using the same ARM template and parameters should give us back the required details of the resources without changing them too much (same naming conventions)
Then the new block of logic for managed identity should then be apply to those existing resources (VMs, storage accounts, RG role)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might need to add end-to-end tests to validate these finally, though maybe in a separate PR.