Skip to content

Commit 60462e0

Browse files
Merge pull request #37 from NHSDigital/DTOSS-12260-create-bootstrap-and-identities
[DTOSS-12260] - feat(bootstrap): add bootstrap Bicep and Terraform make targets for mbsgw
2 parents dd977b3 + 4543cb2 commit 60462e0

14 files changed

Lines changed: 731 additions & 0 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
include scripts/shared.mk
2+
include scripts/terraform/terraform.mk
23

34
.DEFAULT_GOAL := help
45

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ENV_CONFIG=dev
2+
ENVIRONMENT=dev
3+
AZURE_SUBSCRIPTION="Breast Screening - Manage Breast Screening - Dev"
4+
HUB_SUBSCRIPTION="Digital Screening DToS - DevOps"
5+
HUB=dev
6+
TERRAFORM_MODULES_REF=main
7+
ENABLE_SOFT_DELETE=false
8+
ADO_MANAGEMENT_POOL=private-pool-dev-uks
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ENV_CONFIG=preprod
2+
ENVIRONMENT=preprod
3+
AZURE_SUBSCRIPTION="Breast Screening - Manage Breast Screening - Preprod"
4+
HUB_SUBSCRIPTION="Digital Screening DToS - Core Services Prod Hub"
5+
HUB=prod
6+
TERRAFORM_MODULES_REF=main
7+
ENABLE_SOFT_DELETE=false
8+
ADO_MANAGEMENT_POOL=private-pool-prod-uks
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ENV_CONFIG=prod
2+
ENVIRONMENT=prod
3+
AZURE_SUBSCRIPTION="Breast Screening - Manage Breast Screening - Prod"
4+
HUB_SUBSCRIPTION="Digital Screening DToS - Core Services Prod Hub"
5+
HUB=prod
6+
TERRAFORM_MODULES_REF=main
7+
ENABLE_SOFT_DELETE=false
8+
ADO_MANAGEMENT_POOL=private-pool-prod-uks
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ENV_CONFIG=review
2+
ENVIRONMENT=review
3+
AZURE_SUBSCRIPTION="Breast Screening - Manage Breast Screening - Dev"
4+
HUB_SUBSCRIPTION="Digital Screening DToS - DevOps"
5+
HUB=dev
6+
TERRAFORM_MODULES_REF=main
7+
ENABLE_SOFT_DELETE=false
8+
ADO_MANAGEMENT_POOL=private-pool-dev-uks
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
targetScope='subscription'
2+
3+
@minLength(1)
4+
param miPrincipalId string
5+
@minLength(1)
6+
param miName string
7+
@minLength(1)
8+
param userGroupPrincipalID string
9+
@minLength(1)
10+
param userGroupName string
11+
12+
// See: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
13+
var roleID = {
14+
contributor: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
15+
kvSecretsUser: '4633458b-17de-408a-b874-0445c86b69e6' // gitleaks:allow
16+
kvSecretsOfficer: 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7' // gitleaks:allow
17+
rbacAdmin: 'f58310d9-a9f6-439a-9e8d-f62e7b41a168'
18+
storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
19+
storageQueueDataContributor: '974c5e8b-45b9-4653-ba55-5f855dd0fb88'
20+
AzureConnectedMachineOnboarding: 'b64e21ea-ac4e-4cdf-9dc9-5b892992bee7'
21+
}
22+
23+
// Define role assignments for managed identity
24+
var miRoleAssignments = [
25+
{
26+
roleName: 'contributor'
27+
roleId: roleID.contributor
28+
description: 'Contributor access to subscription'
29+
}
30+
{
31+
roleName: 'kvSecretsUser'
32+
roleId: roleID.kvSecretsUser
33+
description: 'kvSecretsUser access to subscription'
34+
}
35+
{
36+
roleName: 'rbacAdmin'
37+
roleId: roleID.rbacAdmin
38+
description: 'RBAC Administrator. Restricted to only assign/remove: Storage Blob Data Contributor, Storage Queue Data Contributor, and Azure Connected Machine Onboarding.'
39+
// Delegated RBAC: This condition restricts the RBAC Administrator to only manage specific roles.
40+
// This is a security best practice that prevents the identity from granting itself or others sensitive roles like 'Owner' or 'User Access Administrator'.
41+
condition: '((!(ActionMatches{\'Microsoft.Authorization/roleAssignments/write\'})) OR (@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${roleID.storageBlobDataContributor}, ${roleID.storageQueueDataContributor}, ${roleID.AzureConnectedMachineOnboarding}})) AND ((!(ActionMatches{\'Microsoft.Authorization/roleAssignments/delete\'})) OR (@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${roleID.storageBlobDataContributor}, ${roleID.storageQueueDataContributor}, ${roleID.AzureConnectedMachineOnboarding}}))'
42+
conditionVersion: '2.0'
43+
}
44+
]
45+
46+
// Define role assignments for Entra ID group
47+
var groupRoleAssignments = [
48+
{
49+
roleName: 'contributor'
50+
roleId: roleID.contributor
51+
description: 'Contributor access to subscription'
52+
}
53+
{
54+
roleName: 'kvSecretsOfficer'
55+
roleId: roleID.kvSecretsOfficer
56+
description: 'kvSecretsOfficer access to subscription'
57+
}
58+
{
59+
roleName: 'rbacAdmin'
60+
roleId: roleID.rbacAdmin
61+
description: 'RBAC Administrator. Restricted to only assign/remove: Storage Blob Data Contributor, Storage Queue Data Contributor, and Azure Connected Machine Onboarding.'
62+
// Delegated RBAC: This condition restricts the RBAC Administrator to only manage specific roles.
63+
// This is a security best practice that prevents the identity from granting itself or others sensitive roles like 'Owner' or 'User Access Administrator'.
64+
condition: '((!(ActionMatches{\'Microsoft.Authorization/roleAssignments/write\'})) OR (@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${roleID.storageBlobDataContributor}, ${roleID.storageQueueDataContributor}, ${roleID.AzureConnectedMachineOnboarding}})) AND ((!(ActionMatches{\'Microsoft.Authorization/roleAssignments/delete\'})) OR (@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {${roleID.storageBlobDataContributor}, ${roleID.storageQueueDataContributor}, ${roleID.AzureConnectedMachineOnboarding}}))'
65+
conditionVersion: '2.0'
66+
}
67+
]
68+
69+
// This creates one resource for each item in the miRoleAssignments array
70+
resource miRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in miRoleAssignments: {
71+
// guid() ensures unique names for each assignment
72+
name: guid(subscription().subscriptionId, miPrincipalId, role.roleName)
73+
properties: {
74+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role.roleId)
75+
principalId: miPrincipalId
76+
principalType: 'ServicePrincipal'
77+
description: '${miName} ${role.description}'
78+
// Conditionally include the 'condition' property only if it exists in the role object
79+
condition: role.?condition
80+
conditionVersion: role.?conditionVersion
81+
}
82+
}]
83+
84+
85+
// This creates one resource for each item in the groupRoleAssignments array
86+
resource groupRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in groupRoleAssignments: {
87+
name: guid(subscription().subscriptionId, userGroupPrincipalID, role.roleName)
88+
properties: {
89+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role.roleId)
90+
principalId: userGroupPrincipalID
91+
principalType: 'Group'
92+
description: '${userGroupName} ${role.description}'
93+
condition: role.?condition
94+
conditionVersion: role.?conditionVersion
95+
}
96+
}]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
param resourceServiceType string
2+
3+
var dnsZoneName = {
4+
storage: 'privatelink.blob.${environment().suffixes.storage}'
5+
// Cannot read vault URL from environment() because of https://github.com/Azure/bicep/issues/9839
6+
keyVault: 'privatelink.vaultcore.azure.net'
7+
}
8+
9+
// Retrieve the private DNS zone for storage accounts
10+
resource privateDNSZone 'Microsoft.Network/privateDnsZones@2024-06-01' existing = {
11+
name: dnsZoneName[resourceServiceType]
12+
}
13+
14+
output privateDNSZoneID string = privateDNSZone.id
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
param enableSoftDelete bool
3+
param keyVaultName string
4+
param miPrincipalId string
5+
param miName string
6+
param region string
7+
param userGroupPrincipalID string
8+
param userGroupName string
9+
10+
// See: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
11+
var roleID = {
12+
kvSecretsUser: '4633458b-17de-408a-b874-0445c86b69e6' // gitleaks:allow
13+
kvSecretsOfficer: 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7' // gitleaks:allow
14+
}
15+
16+
// Define role assignments for managed identity (read-only)
17+
var miRoleAssignments = [
18+
{
19+
roleName: 'kvSecretsUser'
20+
roleId: roleID.kvSecretsUser
21+
description: 'kvSecretsUser access to resource group'
22+
}
23+
]
24+
25+
// Define role assignments for Entra ID group (full management)
26+
var groupRoleAssignments = [
27+
{
28+
roleName: 'kvSecretsOfficer'
29+
roleId: roleID.kvSecretsOfficer
30+
description: 'kvSecretsOfficer access to resource group'
31+
}
32+
]
33+
34+
resource keyVault 'Microsoft.KeyVault/vaults@2024-11-01' = {
35+
name: keyVaultName
36+
location: region
37+
properties: {
38+
tenantId: subscription().tenantId
39+
sku: {
40+
name: 'standard'
41+
family: 'A'
42+
}
43+
enableRbacAuthorization: true
44+
enabledForDeployment: true
45+
enabledForTemplateDeployment: true
46+
enabledForDiskEncryption: true
47+
enableSoftDelete: enableSoftDelete
48+
publicNetworkAccess: 'disabled'
49+
}
50+
}
51+
52+
// Managed identity RBAC assignments using loop
53+
resource miRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in miRoleAssignments: {
54+
name: guid(subscription().subscriptionId, miPrincipalId, role.roleName)
55+
properties: {
56+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role.roleId)
57+
principalId: miPrincipalId
58+
principalType: 'ServicePrincipal'
59+
description: '${miName} ${role.description}'
60+
}
61+
}]
62+
63+
// Entra ID Group RBAC assignments using loop
64+
resource groupRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for role in groupRoleAssignments: {
65+
name: guid(subscription().subscriptionId, userGroupPrincipalID, role.roleName)
66+
properties: {
67+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', role.roleId)
68+
principalId: userGroupPrincipalID
69+
principalType: 'Group'
70+
description: '${userGroupName} ${role.description}'
71+
}
72+
}]
73+
74+
// Output the key vault ID so it can be used to create the private endpoint
75+
output keyVaultID string = keyVault.id

0 commit comments

Comments
 (0)