1818 "defaultValue" : " N/A"
1919 },
2020 "location" : {
21+ "type" : " string"
22+ },
23+ "deploymentTimestamp" : {
2124 "type" : " string" ,
22- "defaultValue" : " UK South"
25+ "defaultValue" : " [utcNow()]"
26+ },
27+ "devopsServicePrincipalId" : {
28+ "type" : " string"
29+ },
30+ "adlsStorageAccountContainerName" : {
31+ "type" : " string" ,
32+ "defaultValue" : " test"
2333 }
2434 },
2535 "variables" : {
26- "storageAccountApiVersion" : " 2019-06-01" ,
27- "storageAccountName" : " [concat('adls', substring(uniqueString(parameters('branch')), 0, 4), 'xxxx', substring(parameters('commit'), 0, min(length(parameters('commit')), 7)))]" ,
28- "storageAccountResourceId" : " [resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
36+ "storageAccountApiVersion" : " 2021-04-01" ,
37+ "adlsStorageAccountName" : " [concat('adls', substring(uniqueString(parameters('branch')), 0, 4), 'xxxx', substring(parameters('commit'), 0, min(length(parameters('commit')), 7)))]" ,
38+ "adlsStorageAccountResourceId" : " [resourceId('Microsoft.Storage/storageAccounts', variables('adlsStorageAccountName'))]" ,
39+ //"adlsStorageAccountContainerName": "test",
40+
41+ "functionsAppApiVersion" : " 2015-08-01" ,
42+ "functionsAppBlobStorageAccountName" : " [concat('funcblob', substring(uniqueString(parameters('branch')), 0, 4), 'xxxx', substring(parameters('commit'), 0, min(length(parameters('commit')), 7)))]" ,
43+ "functionsAppName" : " [concat('func', substring(uniqueString(parameters('branch')), 0, 4), 'xxxx', substring(parameters('commit'), 0, min(length(parameters('commit')), 7)))]" ,
44+
45+ "authorizationApiVersion" : " 2018-09-01-preview" ,
46+
47+ "owner" : " [concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]" ,
48+ "contributor" : " [concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]" ,
49+ "reader" : " [concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]" ,
50+
51+ "storageBlobDataContributor" : " [concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]" ,
52+ "storageBlobDatareader" : " [concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]"
2953 },
3054 "resources" : [
55+ /********************************************************************************************************************************************
56+ **** Resource group permissions
57+ ********************************************************************************************************************************************/
58+
59+ // Add the devops service principal as a contributor on the resource group (DevTest Labs is configured to create an RG for
60+ // each lab).
61+
62+ // 'Reader' scoped to the resource group
63+ {
64+ "type" : " Microsoft.Authorization/roleAssignments" ,
65+ "apiVersion" : " [variables('authorizationApiVersion')]" ,
66+ "name" : " [guid(resourceGroup().id, 'devopsServicePrincipal_rg_contributor')]" ,
67+ "properties" : {
68+ "roleDefinitionId" : " [variables('contributor')]" ,
69+ "principalId" : " [parameters('devopsServicePrincipalId')]"
70+ }
71+ },
72+
73+ // 'Storage Blob Data Reader' scoped to the storage account
74+ {
75+ "type" : " Microsoft.Storage/storageAccounts/providers/roleAssignments" ,
76+ "name" : " [concat(variables('adlsStorageAccountName'),'/Microsoft.Authorization/',guid(resourceGroup().id, 'devopsServicePrincipal_adlsStorageAccount_storageBlobDataReader'))]" ,
77+ "apiVersion" : " [variables('authorizationApiVersion')]" ,
78+ "properties" : {
79+ "roleDefinitionId" : " [variables('storageBlobDatareader')]" ,
80+ "principalId" : " [parameters('devopsServicePrincipalId')]"
81+ },
82+ "dependsOn" : [
83+ " [concat('Microsoft.Storage/storageAccounts/', variables('adlsStorageAccountName'))]"
84+ ]
85+ },
86+
87+ // 'Storage Blob Data Contributor' scoped to the storage account container
88+ {
89+ "type" : " Microsoft.Storage/storageAccounts/blobServices/containers/providers/roleAssignments" ,
90+ //"name": "[concat(variables('adlsStorageAccountName'), '/default/', parameters('adlsStorageAccountContainerName'), '/Microsoft.Authorization/', guid(resourceGroup().id, 'devopsServicePrincipal_adlsStorageAccountContainer', parameters('adlsStorageAccountContainerName'), 'test_storageBlobDataContributor'))]",
91+ "name" : " [concat(variables('adlsStorageAccountName'), '/default/', parameters('adlsStorageAccountContainerName'), '/Microsoft.Authorization/', guid(resourceGroup().id, parameters('devopsServicePrincipalId'), variables('adlsStorageAccountName'), parameters('adlsStorageAccountContainerName'), variables('storageBlobDataContributor')))]" ,
92+ "apiVersion" : " [variables('authorizationApiVersion')]" ,
93+ //"scope": "[concat(resourceGroup().id, '/providers/Microsoft.Storage/storageAccounts/', variables('adlsStorageAccountName'), '/blobServices/containers/containers/', variables('adlsStorageAccountContainerName'))]",
94+ "properties" : {
95+ "roleDefinitionId" : " [variables('storageBlobDataContributor')]" ,
96+ "principalId" : " [parameters('devopsServicePrincipalId')]"
97+ },
98+ "dependsOn" : [
99+ " [concat('Microsoft.Storage/storageAccounts/', variables('adlsStorageAccountName'), '/blobServices/default/containers/', parameters('adlsStorageAccountContainerName'))]"
100+ ]
101+ },
102+
103+ // Add IAM access for functions app. See the following page for details of how to get the object id for the SPN
104+ // https://www.codeisahighway.com/there-is-a-new-way-to-reference-managed-identity-in-arm-template/
105+
106+ // 'Reader' scoped to the storage account
107+ {
108+ "type" : " Microsoft.Storage/storageAccounts/providers/roleAssignments" ,
109+ "name" : " [concat(variables('adlsStorageAccountName'),'/Microsoft.Authorization/',guid(resourceGroup().id, variables('functionsAppName'), variables('adlsStorageAccountName'), parameters('adlsStorageAccountContainerName'), variables('reader')))]" ,
110+ "apiVersion" : " [variables('authorizationApiVersion')]" ,
111+ "properties" : {
112+ "roleDefinitionId" : " [variables('reader')]" ,
113+ "principalId" : " [reference(resourceId('Microsoft.Web/sites', variables('functionsAppName')), variables('functionsAppApiVersion'), 'full').identity.principalId]"
114+ },
115+ "dependsOn" : [
116+ " [concat('Microsoft.Storage/storageAccounts/', variables('adlsStorageAccountName'))]" ,
117+ " [resourceId('Microsoft.Web/sites', variables('functionsAppName'))]"
118+ ]
119+ },
120+
121+ // 'Storage Blob Data Reader' scoped to the storage account
122+ {
123+ "type" : " Microsoft.Storage/storageAccounts/blobServices/containers/providers/roleAssignments" ,
124+ "name" : " [concat(variables('adlsStorageAccountName'), '/default/', parameters('adlsStorageAccountContainerName'), '/Microsoft.Authorization/', guid(resourceGroup().id, variables('functionsAppName'), variables('adlsStorageAccountName'), parameters('adlsStorageAccountContainerName'), variables('storageBlobDatareader')))]" ,
125+ "apiVersion" : " [variables('authorizationApiVersion')]" ,
126+ "properties" : {
127+ "roleDefinitionId" : " [variables('storageBlobDatareader')]" ,
128+ "principalId" : " [reference(resourceId('Microsoft.Web/sites', variables('functionsAppName')), variables('functionsAppApiVersion'), 'full').identity.principalId]"
129+ },
130+ "dependsOn" : [
131+ " [concat('Microsoft.Storage/storageAccounts/', variables('adlsStorageAccountName'))]" ,
132+ " [resourceId('Microsoft.Web/sites', variables('functionsAppName'))]"
133+ ]
134+ },
135+
136+ /********************************************************************************************************************************************
137+ **** ADLS storage
138+ ********************************************************************************************************************************************/
31139 {
32- "name" : " [variables('storageAccountName ')]" ,
140+ "name" : " [variables('adlsStorageAccountName ')]" ,
33141 "type" : " Microsoft.Storage/storageAccounts" ,
34142 "apiVersion" : " [variables('storageAccountApiVersion')]" ,
35143 "location" : " [parameters('location')]" ,
36144 "properties" : {
37145 "accessTier" : " Hot" ,
38146 "minimumTlsVersion" : " TLS1_2" ,
39147 "supportsHttpsTrafficOnly" : true ,
40- "allowBlobPublicAccess" : true ,
148+ "allowBlobPublicAccess" : false ,
41149 "allowSharedKeyAccess" : true ,
42150 "isHnsEnabled" : true ,
43151 "networkAcls" : {
44152 "bypass" : " AzureServices" ,
45153 "defaultAction" : " Allow"
46154 }
47155 },
48- "dependsOn" : [],
156+ "dependsOn" : [
157+ " [resourceId('Microsoft.Web/sites', variables('functionsAppName'))]"
158+ ],
49159 "sku" : {
50160 "name" : " Standard_LRS"
51161 },
55165 "Commit" : " [parameters('commit')]" ,
56166 "Branch" : " [parameters('branch')]" ,
57167 "Pull Request" : " [parameters('pullRequest')]" ,
58- "Create Date Time" : " 2021-04-28T12:08:00"
168+ "Create Date Time" : " [parameters('deploymentTimestamp')]" ,
169+ "Git Project Resource Code" : " ADLS" ,
170+ "RG" : " [resourceGroup().name]"
171+ },
172+ "resources" : [
173+ // Add a container to the storage account
174+ {
175+ "name" : " [concat('default/', parameters('adlsStorageAccountContainerName'))]" ,
176+ "type" : " blobServices/containers" ,
177+ "apiVersion" : " [variables('storageAccountApiVersion')]" ,
178+ "properties" : {
179+ "publicAccess" : " None"
180+ },
181+ "dependsOn" : [
182+ " [variables('adlsStorageAccountName')]"
183+ ]
184+ }
185+ ]
186+ },
187+
188+
189+ /********************************************************************************************************************************************
190+ **** Functions Apps
191+ ********************************************************************************************************************************************/
192+
193+ // Blob storage for the functions app
194+ {
195+ "apiVersion" : " [variables('storageAccountApiVersion')]" ,
196+ "type" : " Microsoft.Storage/storageAccounts" ,
197+ "name" : " [variables('functionsAppBlobStorageAccountName')]" ,
198+ "location" : " [parameters('location')]" ,
199+ "tags" : {
200+ "Git Project" : " [parameters('gitProject')]" ,
201+ "Commit" : " [parameters('commit')]" ,
202+ "Branch" : " [parameters('branch')]" ,
203+ "Pull Request" : " [parameters('pullRequest')]" ,
204+ "Create Date Time" : " [parameters('deploymentTimestamp')]" ,
205+ "Git Project Resource Code" : " FunctionsAppStorage"
206+ },
207+ "sku" : {
208+ "name" : " Standard_LRS"
209+ },
210+ "properties" : {
211+ "supportsHttpsTrafficOnly" : true ,
212+ "minimumTlsVersion" : " TLS1_2"
213+ }
214+ },
215+
216+ // Functions app, cofigured to use .Net Core 3.X with the blob storage above
217+ {
218+ "apiVersion" : " [variables('functionsAppApiVersion')]" ,
219+ "type" : " Microsoft.Web/sites" ,
220+ "name" : " [variables('functionsAppName')]" ,
221+ "location" : " [parameters('location')]" ,
222+ "kind" : " functionapp" ,
223+ "identity" : {
224+ "type" : " SystemAssigned"
225+ },
226+ "dependsOn" : [
227+ " [resourceId('Microsoft.Storage/storageAccounts', variables('functionsAppBlobStorageAccountName'))]"
228+ ],
229+ "tags" : {
230+ "Git Project" : " [parameters('gitProject')]" ,
231+ "Commit" : " [parameters('commit')]" ,
232+ "Branch" : " [parameters('branch')]" ,
233+ "Pull Request" : " [parameters('pullRequest')]" ,
234+ "Create Date Time" : " [parameters('deploymentTimestamp')]" ,
235+ "Git Project Resource Code" : " FunctionsApp"
236+ },
237+ "properties" : {
238+ "siteConfig" : {
239+ "appSettings" : [
240+ {
241+ "name" : " FUNCTIONS_EXTENSION_VERSION" ,
242+ "value" : " ~3"
243+ },
244+ {
245+ "name" : " FUNCTIONS_WORKER_RUNTIME" ,
246+ "value" : " dotnet"
247+ },
248+ {
249+ "name" : " AzureWebJobsStorage" ,
250+ "value" : " [concat('DefaultEndpointsProtocol=https;AccountName=',variables('functionsAppBlobStorageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('functionsAppBlobStorageAccountName')), variables('storageAccountApiVersion')).keys[0].value,';EndpointSuffix=','core.windows.net')]"
251+ }
252+ ]
253+ }
59254 }
60255 }
61256 ],
257+
258+ /********************************************************************************************************************************************
259+ **** Outputs, does not seem to help when deploying uzing the Azure CLI 'az lab environment create' command
260+ ********************************************************************************************************************************************/
261+
62262 "outputs" : {
63263 "storageAccountName" : {
64264 "type" : " string" ,
65- "value" : " [variables('storageAccountName ')]"
265+ "value" : " [variables('adlsStorageAccountName ')]"
66266 },
67267 "storageAccountConnectionString" : {
68268 "type" : " string" ,
69- "value" : " [concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName '), ';AccountKey=', listKeys(variables('storageAccountResourceId '), variables('storageAccountApiVersion')).keys[0].value)]"
269+ "value" : " [concat('DefaultEndpointsProtocol=https;AccountName=', variables('adlsStorageAccountName '), ';AccountKey=', listKeys(variables('adlsStorageAccountResourceId '), variables('storageAccountApiVersion')).keys[0].value)]"
70270 }
71271 }
72272}
0 commit comments