From cdc8a6f483f4efffdfa2ca823d49057efb529437 Mon Sep 17 00:00:00 2001 From: Tanmay Satam Date: Tue, 11 Feb 2025 14:11:55 -0500 Subject: [PATCH] Add devops identity as Storage Blob Data Contributor to rpversion SA --- pkg/deploy/assets/rp-production-global.json | 17 +++ pkg/deploy/generator/resources_rp.go | 10 +- pkg/deploy/generator/templates_rp.go | 1 + pkg/deploy/predeploy.go | 12 +- pkg/deploy/predeploy_test.go | 117 +++++++++++++------- pkg/util/rbac/rbac.go | 1 + 6 files changed, 118 insertions(+), 40 deletions(-) diff --git a/pkg/deploy/assets/rp-production-global.json b/pkg/deploy/assets/rp-production-global.json index 71f669ef7c3..257552bf0d2 100644 --- a/pkg/deploy/assets/rp-production-global.json +++ b/pkg/deploy/assets/rp-production-global.json @@ -18,6 +18,9 @@ "gatewayServicePrincipalId": { "type": "string" }, + "globalDevopsServicePrincipalId": { + "type": "string" + }, "rpParentDomainName": { "type": "string" }, @@ -111,6 +114,20 @@ "name": "[parameters('rpVersionStorageAccountName')]", "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2021-09-01" + }, + { + "name": "[concat(parameters('rpVersionStorageAccountName'), '/Microsoft.Authorization/', guid(resourceId('Microsoft.Storage/storageAccounts', parameters('rpVersionStorageAccountName'))))]", + "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments", + "properties": { + "scope": "[resourceId('Microsoft.Storage/storageAccounts', parameters('rpVersionStorageAccountName'))]", + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '17d1049b-9a84-46fb-8f53-869881c3d3ab')]", + "principalId": "[parameters('globalDevopsServicePrincipalId')]", + "principalType": "ServicePrincipal" + }, + "apiVersion": "2018-09-01-preview", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('rpVersionStorageAccountName'))]" + ] } ] } diff --git a/pkg/deploy/generator/resources_rp.go b/pkg/deploy/generator/resources_rp.go index 1f375969acc..b26f312b421 100644 --- a/pkg/deploy/generator/resources_rp.go +++ b/pkg/deploy/generator/resources_rp.go @@ -1517,14 +1517,22 @@ func (g *generator) rpACRRBAC() []*arm.Resource { } func (g *generator) rpVersionStorageAccount() []*arm.Resource { + storageAccountName := "parameters('rpVersionStorageAccountName')" return []*arm.Resource{ g.storageAccount( - "[parameters('rpVersionStorageAccountName')]", + fmt.Sprintf("[%s]", storageAccountName), &mgmtstorage.AccountProperties{ AllowBlobPublicAccess: to.BoolPtr(false), MinimumTLSVersion: mgmtstorage.MinimumTLSVersionTLS12, }, map[string]*string{}, ), + rbac.ResourceRoleAssignmentWithName( + rbac.RoleStorageAccountContributor, + "parameters('globalDevopsServicePrincipalId')", + resourceTypeStorageAccount, + storageAccountName, + fmt.Sprintf("concat(%s, '/Microsoft.Authorization/', guid(resourceId('%s', %s)))", storageAccountName, resourceTypeStorageAccount, storageAccountName), + ), } } diff --git a/pkg/deploy/generator/templates_rp.go b/pkg/deploy/generator/templates_rp.go index 0e0518c022c..b41a1ddcd79 100644 --- a/pkg/deploy/generator/templates_rp.go +++ b/pkg/deploy/generator/templates_rp.go @@ -193,6 +193,7 @@ func (g *generator) rpGlobalTemplate() *arm.Template { "rpParentDomainName", "rpServicePrincipalId", "rpVersionStorageAccountName", + "globalDevopsServicePrincipalId", } for _, param := range params { diff --git a/pkg/deploy/predeploy.go b/pkg/deploy/predeploy.go index e34874d5101..2836fad0f8e 100644 --- a/pkg/deploy/predeploy.go +++ b/pkg/deploy/predeploy.go @@ -107,8 +107,13 @@ func (d *deployer) PreDeploy(ctx context.Context, lbHealthcheckWaitTimeSec int) return err } + globalDevopsMSI, err := d.globaluserassignedidentities.Get(ctx, *d.config.Configuration.GlobalResourceGroupName, *d.config.Configuration.GlobalDevopsManagedIdentity) + if err != nil { + return err + } + // deploy ACR RBAC, RP version storage account - err = d.deployRPGlobal(ctx, rpMSI.PrincipalID.String(), gwMSI.PrincipalID.String()) + err = d.deployRPGlobal(ctx, rpMSI.PrincipalID.String(), gwMSI.PrincipalID.String(), globalDevopsMSI.PrincipalID.String()) if err != nil { return err } @@ -157,7 +162,7 @@ func (d *deployer) PreDeploy(ctx context.Context, lbHealthcheckWaitTimeSec int) return d.configureServiceSecrets(ctx, lbHealthcheckWaitTimeSec) } -func (d *deployer) deployRPGlobal(ctx context.Context, rpServicePrincipalID, gatewayServicePrincipalID string) error { +func (d *deployer) deployRPGlobal(ctx context.Context, rpServicePrincipalID, gatewayServicePrincipalID, devopsServicePrincipalId string) error { deploymentName := "rp-global-" + d.config.Location asset, err := assets.EmbeddedFiles.ReadFile(generator.FileRPProductionGlobal) @@ -178,6 +183,9 @@ func (d *deployer) deployRPGlobal(ctx context.Context, rpServicePrincipalID, gat parameters.Parameters["gatewayServicePrincipalId"] = &arm.ParametersParameter{ Value: gatewayServicePrincipalID, } + parameters.Parameters["globalDevopsServicePrincipalId"] = &arm.ParametersParameter{ + Value: devopsServicePrincipalId, + } for i := 0; i < 2; i++ { d.log.Infof("deploying %s", deploymentName) diff --git a/pkg/deploy/predeploy_test.go b/pkg/deploy/predeploy_test.go index 4a15791f524..a790da5c5ac 100644 --- a/pkg/deploy/predeploy_test.go +++ b/pkg/deploy/predeploy_test.go @@ -89,6 +89,7 @@ func TestPreDeploy(t *testing.T) { rpRgName := "testRG-aro-rp" gatewayRgName := "testRG-gwy" overrideLocation := "overrideTestLocation" + globalDevopsManagedIdentity := "aro-test-devops" group := mgmtfeatures.ResourceGroup{ Location: &location, @@ -112,13 +113,14 @@ func TestPreDeploy(t *testing.T) { gatewayResourceGroupName string } type testParams struct { - resourceGroups resourceGroups - location string - instanceID string - vmssName string - restartScript string - overrideLocation string - acrReplicaDisabled bool + resourceGroups resourceGroups + location string + instanceID string + vmssName string + restartScript string + overrideLocation string + globalDevopsManagedIdentity string + acrReplicaDisabled bool } type mock func(*mock_features.MockDeploymentsClient, *mock_features.MockResourceGroupsClient, *mock_msi.MockUserAssignedIdentitiesClient, *mock_keyvault.MockManager, *mock_compute.MockVirtualMachineScaleSetsClient, *mock_compute.MockVirtualMachineScaleSetVMsClient, testParams) createOrUpdateAtSubscriptionScopeAndWaitMock := func(returnError error) mock { @@ -183,7 +185,8 @@ func TestPreDeploy(t *testing.T) { { name: "don't continue if Global Subscription RBAC DeploymentFailed", testParams: testParams{ - location: location, + location: location, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(errGeneric), @@ -197,6 +200,7 @@ func TestPreDeploy(t *testing.T) { resourceGroups: resourceGroups{ subscriptionRGName: subscriptionRGName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, errGeneric), @@ -211,6 +215,7 @@ func TestPreDeploy(t *testing.T) { subscriptionRGName: subscriptionRGName, globalResourceGroup: globalRGName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, errGeneric), @@ -226,6 +231,7 @@ func TestPreDeploy(t *testing.T) { globalResourceGroup: globalRGName, rpResourceGroupName: rpRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, errGeneric), @@ -242,6 +248,7 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, errGeneric), @@ -258,6 +265,7 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, errGeneric), @@ -274,6 +282,7 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, errGeneric), @@ -290,12 +299,30 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, errGeneric), }, wantErr: "generic error", }, + { + name: "don't continue if rp and gateway managed identity gets are successful but devops managed identity get fails", + testParams: testParams{ + location: location, + resourceGroups: resourceGroups{ + subscriptionRGName: subscriptionRGName, + globalResourceGroup: globalRGName, + rpResourceGroupName: rpRgName, + gatewayResourceGroupName: gatewayRgName, + }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + }, + mocks: []mock{ + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, errGeneric), + }, + wantErr: "generic error", + }, { name: "don't continue if rpglobal deployment fails", testParams: testParams{ @@ -306,9 +333,10 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, errGeneric), }, wantErr: "generic error", }, @@ -322,9 +350,10 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, deploymentFailedError), createOrUpdateAndWaitMock(globalRGName, deploymentFailedError), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, deploymentFailedError), createOrUpdateAndWaitMock(globalRGName, deploymentFailedError), }, wantErr: `Code="DeploymentFailed" Message="" Details=[{}]`, }, @@ -338,10 +367,11 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: overrideLocation, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: overrideLocation, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, errGeneric), }, wantErr: "generic error", }, @@ -355,9 +385,10 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), }, wantErr: "generic error", }, @@ -371,10 +402,11 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: location, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: location, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), }, wantErr: "generic error", }, @@ -388,11 +420,12 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: overrideLocation, - acrReplicaDisabled: true, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: overrideLocation, + acrReplicaDisabled: true, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, errGeneric), }, wantErr: "generic error", }, @@ -406,11 +439,12 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: overrideLocation, - acrReplicaDisabled: true, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: overrideLocation, + acrReplicaDisabled: true, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, errGeneric), }, wantErr: "generic error", }, @@ -424,11 +458,12 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: overrideLocation, - acrReplicaDisabled: true, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: overrideLocation, + acrReplicaDisabled: true, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, nil), getSecretsMock(oneMissingSecretItems, errGeneric), + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, nil), getSecretsMock(oneMissingSecretItems, errGeneric), }, wantErr: "generic error", }, @@ -442,14 +477,15 @@ func TestPreDeploy(t *testing.T) { rpResourceGroupName: rpRgName, gatewayResourceGroupName: gatewayRgName, }, - overrideLocation: overrideLocation, - acrReplicaDisabled: true, - vmssName: vmssName, - instanceID: instanceID, - restartScript: rpRestartScript, + globalDevopsManagedIdentity: globalDevopsManagedIdentity, + overrideLocation: overrideLocation, + acrReplicaDisabled: true, + vmssName: vmssName, + instanceID: instanceID, + restartScript: rpRestartScript, }, mocks: []mock{ - createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, nil), getSecretsMock(oneMissingSecretItems, nil), setSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretsMock(oneMissingSecretItems, nil), getSecretsMock(oneMissingSecretItems, nil), vmssListMock, vmssVMsListMock, vmRestartMock, instanceViewMock, + createOrUpdateAtSubscriptionScopeAndWaitMock(nil), createOrUpdateMock(subscriptionRGName, group, nil), createOrUpdateMock(globalRGName, group, nil), createOrUpdateMock(rpRgName, group, nil), createOrUpdateMock(gatewayRgName, group, nil), createOrUpdateAndWaitMock(subscriptionRGName, nil), createOrUpdateAndWaitMock(rpRgName, nil), msiGetMock(rpRgName, nil), createOrUpdateAndWaitMock(gatewayRgName, nil), msiGetMock(gatewayRgName, nil), msiGetMock(globalRGName, nil), createOrUpdateAndWaitMock(globalRGName, nil), getDeploymentMock(deploymentNotFoundError), createOrUpdateAndWaitMock(gatewayRgName, nil), createOrUpdateAndWaitMock(rpRgName, nil), getSecretsMock(oneMissingSecretItems, nil), setSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretMock, getSecretsMock(oneMissingSecretItems, nil), getSecretsMock(oneMissingSecretItems, nil), getSecretsMock(oneMissingSecretItems, nil), vmssListMock, vmssVMsListMock, vmRestartMock, instanceViewMock, }, }, } { @@ -465,12 +501,13 @@ func TestPreDeploy(t *testing.T) { mockVMSSVM := mock_compute.NewMockVirtualMachineScaleSetVMsClient(controller) d := deployer{ - log: logrus.NewEntry(logrus.StandardLogger()), - globaldeployments: mockDeployments, - deployments: mockDeployments, - groups: mockResourceGroups, - globalgroups: mockResourceGroups, - userassignedidentities: mockMSIs, + log: logrus.NewEntry(logrus.StandardLogger()), + globaldeployments: mockDeployments, + deployments: mockDeployments, + groups: mockResourceGroups, + globalgroups: mockResourceGroups, + userassignedidentities: mockMSIs, + globaluserassignedidentities: mockMSIs, config: &RPConfig{ Configuration: &Configuration{ GlobalResourceGroupLocation: &tt.testParams.location, @@ -479,6 +516,7 @@ func TestPreDeploy(t *testing.T) { GlobalResourceGroupName: &tt.testParams.resourceGroups.globalResourceGroup, ACRLocationOverride: &tt.testParams.overrideLocation, ACRReplicaDisabled: &tt.testParams.acrReplicaDisabled, + GlobalDevopsManagedIdentity: &tt.testParams.globalDevopsManagedIdentity, }, RPResourceGroupName: tt.testParams.resourceGroups.rpResourceGroupName, GatewayResourceGroupName: tt.testParams.resourceGroups.gatewayResourceGroupName, @@ -705,12 +743,14 @@ func TestDeployRPGlobal(t *testing.T) { ctx := context.Background() rpSPID := "rpSPIDTest" gwySPID := "gwySPIDTest" + devopsSPID := "devopsSPIDTest" type testParams struct { resourceGroup string location string rpSPID string gwySPID string + devopsSPID string } type mock func(*mock_features.MockDeploymentsClient, testParams) CreateOrUpdateAndWaitMock := func(returnError error) mock { @@ -732,6 +772,7 @@ func TestDeployRPGlobal(t *testing.T) { resourceGroup: globalRGName, rpSPID: rpSPID, gwySPID: gwySPID, + devopsSPID: devopsSPID, }, mocks: []mock{CreateOrUpdateAndWaitMock(errGeneric)}, wantErr: "generic error", @@ -743,6 +784,7 @@ func TestDeployRPGlobal(t *testing.T) { resourceGroup: globalRGName, rpSPID: rpSPID, gwySPID: gwySPID, + devopsSPID: devopsSPID, }, mocks: []mock{CreateOrUpdateAndWaitMock(deploymentFailedError), CreateOrUpdateAndWaitMock(deploymentFailedError)}, wantErr: `Code="DeploymentFailed" Message="" Details=[{}]`, @@ -754,6 +796,7 @@ func TestDeployRPGlobal(t *testing.T) { resourceGroup: globalRGName, rpSPID: rpSPID, gwySPID: gwySPID, + devopsSPID: devopsSPID, }, mocks: []mock{CreateOrUpdateAndWaitMock(deploymentFailedError), CreateOrUpdateAndWaitMock(nil)}, }, @@ -779,7 +822,7 @@ func TestDeployRPGlobal(t *testing.T) { m(mockDeployments, tt.testParams) } - err := d.deployRPGlobal(ctx, tt.testParams.rpSPID, tt.testParams.gwySPID) + err := d.deployRPGlobal(ctx, tt.testParams.rpSPID, tt.testParams.gwySPID, tt.testParams.devopsSPID) utilerror.AssertErrorMessage(t, err, tt.wantErr) }) } diff --git a/pkg/util/rbac/rbac.go b/pkg/util/rbac/rbac.go index 2821c0a3cb0..5d05a282f1e 100644 --- a/pkg/util/rbac/rbac.go +++ b/pkg/util/rbac/rbac.go @@ -20,6 +20,7 @@ const ( RoleNetworkContributor = "4d97b98b-1d4f-4787-a291-c67834d212e7" RoleOwner = "8e3af657-a8ff-443c-a75c-2fe8c4bcb635" RoleReader = "acdd72a7-3385-48ef-bd42-f606fba81ae7" + RoleStorageAccountContributor = "17d1049b-9a84-46fb-8f53-869881c3d3ab" RoleStorageBlobDataContributor = "ba92f5b4-2d11-453d-a403-e96b0029c9fe" RoleKeyVaultSecretsOfficer = "b86a8fe4-44ce-4948-aee5-eccb2c155cd7" RoleAzureRedHatOpenShiftFederatedCredentialRole = "ef318e2a-8334-4a05-9e4a-295a196c6a6e"