-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrg.bicep
More file actions
202 lines (181 loc) · 6.68 KB
/
Copy pathrg.bicep
File metadata and controls
202 lines (181 loc) · 6.68 KB
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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// This file creates all the resource group scope resources
targetScope = 'resourceGroup'
@description('Unique suffix')
param suffix string = uniqueString(resourceGroup().id)
@description('The location of the resources')
param location string = resourceGroup().location
@description('The name of the function app to use')
param appName string = 'debfnapp${suffix}'
@description('Using shared keys or managed identity')
param use_shared_keys bool = true
@description('Enable GPG signing of the repository Release file')
param signing_enabled bool = false
@description('ASCII-armored GPG private key used to sign the repository. Only used when signing_enabled is true.')
@secure()
param gpg_private_key string = ''
@description('ASCII-armored GPG public key, published for clients to verify against. Only used when signing_enabled is true.')
param gpg_public_key string = ''
// Storage account names must be between 3 and 24 characters, and unique, so
// generate a unique name.
@description('The name of the storage account to use')
param storage_account_name string = 'debianrepo${suffix}'
// Choose the package container name. This will be passed to the function app.
var package_container_name = 'packages'
// Create a container for the Python code
var python_container_name = 'python'
// Create a UAMI for the deployment script to access the storage account
resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: 'uami${suffix}'
location: location
}
// Create a storage account for both package storage and function app storage
var common_storage_properties = {
publicNetworkAccess: 'Enabled'
allowBlobPublicAccess: false
minimumTlsVersion: 'TLS1_2'
}
var storage_properties = use_shared_keys ? common_storage_properties : union(common_storage_properties, {
allowSharedKeyAccess: false
})
resource storageAccount 'Microsoft.Storage/storageAccounts@2025-08-01' = {
name: storage_account_name
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: storage_properties
}
// Create a container for the packages
resource defBlobServices 'Microsoft.Storage/storageAccounts/blobServices@2025-08-01' = {
parent: storageAccount
name: 'default'
}
resource packageContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2025-08-01' = {
parent: defBlobServices
name: package_container_name
properties: {
}
}
resource pythonContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2025-08-01' = {
parent: defBlobServices
name: python_container_name
properties: {
}
}
// Grant the UAMI Storage Blob Data Contributor on the storage account
@description('This is the built-in Storage Blob Data Contributor role. See https://learn.microsoft.com/en-gb/azure/role-based-access-control/built-in-roles#storage-blob-data-contributor')
resource storageBlobDataContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
scope: subscription()
name: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
}
resource storageBlobDataContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storageAccount.id, uami.id, storageBlobDataContributor.id)
scope: storageAccount
properties: {
principalId: uami.properties.principalId
roleDefinitionId: storageBlobDataContributor.id
principalType: 'ServicePrincipal'
}
}
// When signing is enabled, create a Key Vault holding the GPG private key.
// The function app's managed identity is granted read access (see
// rg_funcapp.bicep) and the key is surfaced to the function via a Key Vault
// reference app setting.
var key_vault_name = 'debkv${suffix}'
var gpg_secret_name = 'gpg-private-key'
var public_key_blob = 'public-key.asc'
resource keyVault 'Microsoft.KeyVault/vaults@2024-11-01' = if (signing_enabled) {
name: key_vault_name
location: location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: tenant().tenantId
// Use Azure RBAC for data-plane access so the function's managed identity
// can be granted the built-in 'Key Vault Secrets User' role.
enableRbacAuthorization: true
enableSoftDelete: true
}
}
resource gpgSecret 'Microsoft.KeyVault/vaults/secrets@2024-11-01' = if (signing_enabled) {
parent: keyVault
name: gpg_secret_name
properties: {
value: gpg_private_key
}
}
// Create a default Packages file if it doesn't exist using a deployment script
resource deploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
name: 'createPackagesFile${suffix}'
dependsOn: [storageBlobDataContributorRoleAssignment]
location: location
kind: 'AzureCLI'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${uami.id}': {}
}
}
properties: {
azCliVersion: '2.28.0'
retentionInterval: 'PT1H'
environmentVariables: [
{
name: 'AZURE_STORAGE_ACCOUNT'
value: storageAccount.name
}
{
name: 'AZURE_BLOB_CONTAINER'
value: packageContainer.name
}
{
name: 'PUBLIC_KEY'
value: gpg_public_key
}
{
name: 'PUBLIC_KEY_BLOB'
value: public_key_blob
}
]
// This script preserves the Packages file if it exists and creates it
// if it does not. When signing is enabled it also publishes the public key.
// It runs as the UAMI, which holds the Storage Blob Data Contributor role,
// so it works even when shared-key access is disabled.
scriptContent: '''
az storage blob download --auth-mode login -f Packages -c "${AZURE_BLOB_CONTAINER}" -n Packages || echo "No existing file"
touch Packages
az storage blob upload --auth-mode login -f Packages -c "${AZURE_BLOB_CONTAINER}" -n Packages
if [ -n "${PUBLIC_KEY}" ]; then
printf '%s' "${PUBLIC_KEY}" > public_key.asc
az storage blob upload --auth-mode login -f public_key.asc -c "${AZURE_BLOB_CONTAINER}" -n "${PUBLIC_KEY_BLOB}"
fi
'''
cleanupPreference: 'OnSuccess'
}
}
// Create the function app directly
module funcapp 'rg_funcapp.bicep' = {
name: 'funcapp${suffix}'
params: {
location: location
storage_account_name: storageAccount.name
appName: appName
use_shared_keys: use_shared_keys
suffix: suffix
signing_enabled: signing_enabled
key_vault_name: key_vault_name
gpg_key_name: gpg_secret_name
}
}
// Emit the facts needed to construct an apt sources line; the client builds
// the actual string (see create_resources.py).
output public_key_blob string = public_key_blob
output function_app_name string = appName
output storage_account string = storageAccount.name
output package_container string = packageContainer.name
output python_container string = pythonContainer.name