Skip to content

Commit c7059e1

Browse files
Milestone 1.7.0 (#78)
1 parent 625398c commit c7059e1

File tree

35 files changed

+658
-163
lines changed

35 files changed

+658
-163
lines changed

infrastructure/afd-apim-pe/create.ipynb

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@
3838
" PolicyFragment('AuthZ-Match-All', utils.read_policy_xml(utils.determine_shared_policy_path('pf-authz-match-all.xml')), 'Authorizes if all of the specified roles match the JWT role claims.'),\n",
3939
" PolicyFragment('AuthZ-Match-Any', utils.read_policy_xml(utils.determine_shared_policy_path('pf-authz-match-any.xml')), 'Authorizes if any of the specified roles match the JWT role claims.'),\n",
4040
" PolicyFragment('Http-Response-200', utils.read_policy_xml(utils.determine_shared_policy_path('pf-http-response-200.xml')), 'Returns a 200 OK response for the current HTTP method.'),\n",
41+
" PolicyFragment('Product-Match-Any', utils.read_policy_xml(utils.determine_shared_policy_path('pf-product-match-any.xml')), 'Proceeds if any of the specified products match the context product name.'),\n",
4142
" PolicyFragment('Remove-Request-Headers', utils.read_policy_xml(utils.determine_shared_policy_path('pf-remove-request-headers.xml')), 'Removes request headers from the incoming request.')\n",
4243
"]\n",
4344
"\n",
4445
"# 4) Define the APIs and their operations and policies\n",
4546
"\n",
4647
"# Policies\n",
47-
"hello_world_policy_xml = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
48+
"pol_hello_world = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
4849
"\n",
4950
"# Hello World (Root)\n",
50-
"api_hwroot_get = GET_APIOperation('This is a GET for API 1', hello_world_policy_xml)\n",
51+
"api_hwroot_get = GET_APIOperation('This is a GET for API 1', pol_hello_world)\n",
5152
"api_hwroot = API('hello-world', 'Hello World', '', 'This is the root API for Hello World', operations = [api_hwroot_get])\n",
5253
"\n",
5354
"apis: List[API] = [api_hwroot]\n",
@@ -56,22 +57,22 @@
5657
"if use_ACA:\n",
5758
" utils.print_info('ACA APIs will be created.')\n",
5859
"\n",
59-
" backend_policy_xml = utils.read_policy_xml(BACKEND_XML_POLICY_PATH)\n",
60-
" aca_backend_1_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-1')\n",
61-
" aca_backend_2_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-2')\n",
62-
" aca_backend_pool_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-pool')\n",
60+
" pol_backend = utils.read_policy_xml(BACKEND_XML_POLICY_PATH)\n",
61+
" pol_aca_backend_1 = pol_backend.format(backend_id = 'aca-backend-1')\n",
62+
" pol_aca_backend_2 = pol_backend.format(backend_id = 'aca-backend-2')\n",
63+
" pol_aca_backend_pool = pol_backend.format(backend_id = 'aca-backend-pool')\n",
6364
"\n",
6465
" # Hello World (ACA Backend 1)\n",
6566
" api_hwaca_1_get = GET_APIOperation('This is a GET for Hello World on ACA Backend 1')\n",
66-
" api_hwaca_1 = API('hello-world-aca-1', 'Hello World (ACA 1)', '/aca-1', 'This is the ACA API for Backend 1', policyXml = aca_backend_1_policy_xml, operations = [api_hwaca_1_get])\n",
67+
" api_hwaca_1 = API('hello-world-aca-1', 'Hello World (ACA 1)', '/aca-1', 'This is the ACA API for Backend 1', policyXml = pol_aca_backend_1, operations = [api_hwaca_1_get])\n",
6768
"\n",
6869
" # Hello World (ACA Backend 2)\n",
6970
" api_hwaca_2_get = GET_APIOperation('This is a GET for Hello World on ACA Backend 2')\n",
70-
" api_hwaca_2 = API('hello-world-aca-2', 'Hello World (ACA 2)', '/aca-2', 'This is the ACA API for Backend 2', policyXml = aca_backend_2_policy_xml, operations = [api_hwaca_2_get])\n",
71+
" api_hwaca_2 = API('hello-world-aca-2', 'Hello World (ACA 2)', '/aca-2', 'This is the ACA API for Backend 2', policyXml = pol_aca_backend_2, operations = [api_hwaca_2_get])\n",
7172
"\n",
7273
" # Hello World (ACA Backend Pool)\n",
7374
" api_hwaca_pool_get = GET_APIOperation('This is a GET for Hello World on ACA Backend Pool')\n",
74-
" api_hwaca_pool = API('hello-world-aca-pool', 'Hello World (ACA Pool)', '/aca-pool', 'This is the ACA API for Backend Pool', policyXml = aca_backend_pool_policy_xml, operations = [api_hwaca_pool_get])\n",
75+
" api_hwaca_pool = API('hello-world-aca-pool', 'Hello World (ACA Pool)', '/aca-pool', 'This is the ACA API for Backend Pool', policyXml = pol_aca_backend_pool, operations = [api_hwaca_pool_get])\n",
7576
"\n",
7677
" # Add ACA APIs to the existing apis array\n",
7778
" apis += [api_hwaca_1, api_hwaca_2, api_hwaca_pool]\n",
@@ -117,6 +118,7 @@
117118
" apim_service_id = output.get('apimServiceId', 'APIM Service Id')\n",
118119
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
119120
" afd_endpoint_url = output.get('fdeSecureUrl', 'Front Door Endpoint URL')\n",
121+
" apim_apis = output.getJson('apiOutputs', 'APIs')\n",
120122
"\n",
121123
"utils.print_ok('Deployment completed')\n"
122124
]
@@ -186,9 +188,11 @@
186188
"from apimrequests import ApimRequests\n",
187189
"from apimtesting import ApimTesting\n",
188190
"\n",
189-
"reqs = ApimRequests(apim_gateway_url)\n",
190191
"tests = ApimTesting(\"AFD-APIM-PE Tests (Pre-Lockdown)\", deployment, deployment)\n",
191192
"\n",
193+
"api_subscription_key = apim_apis[0]['subscriptionPrimaryKey']\n",
194+
"reqs = ApimRequests(apim_gateway_url, api_subscription_key)\n",
195+
"\n",
192196
"utils.print_message('Calling Hello World (Root) API via API Management Gateway URL. Expect 200 (if run before disabling API Management public network access).')\n",
193197
"output = reqs.singleGet('/')\n",
194198
"tests.verify(output, 'Hello World from API Management!')\n",
@@ -227,8 +231,9 @@
227231
" raise SystemExit('Deployment failed')\n",
228232
" \n",
229233
"if output.success and output.json_data:\n",
230-
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
231234
" afd_endpoint_url = output.get('fdeSecureUrl', 'Front Door Endpoint URL')\n",
235+
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
236+
" apim_apis = output.getJson('apiOutputs', 'APIs')\n",
232237
"\n",
233238
"utils.print_ok('Deployment completed')\n"
234239
]
@@ -249,35 +254,47 @@
249254
"outputs": [],
250255
"source": [
251256
"import utils\n",
252-
"import json\n",
253257
"from apimrequests import ApimRequests\n",
254258
"from apimtesting import ApimTesting\n",
255259
"\n",
256-
"reqsApim = ApimRequests(apim_gateway_url)\n",
257-
"reqsAfd = ApimRequests(afd_endpoint_url)\n",
258260
"tests = ApimTesting(\"AFD-APIM-PE Tests (Post-Lockdown)\", deployment, deployment)\n",
259261
"\n",
262+
"api_subscription_key = apim_apis[0]['subscriptionPrimaryKey']\n",
263+
"reqsApim = ApimRequests(apim_gateway_url, api_subscription_key)\n",
264+
"reqsAfd = ApimRequests(afd_endpoint_url, api_subscription_key)\n",
265+
"\n",
260266
"# 1) Unsuccessful call to APIM Gateway URL (should fail with 403 Forbidden)\n",
261267
"output = reqsApim.singleGet('/', msg = '1) Calling Hello World (Root) API via API Management Gateway URL. Expect 403 as APIM public access is disabled now.')\n",
262-
"tests.verify(json.loads(output)['statusCode'], 403)\n",
268+
"outputJson = utils.get_json(output)\n",
269+
"tests.verify(outputJson['statusCode'], 403)\n",
263270
"\n",
264271
"# 2) Successful call to Front Door (200)\n",
265272
"output = reqsAfd.singleGet('/', msg = '2) Calling Hello World (Root) API via Azure Front Door. Expect 200.')\n",
266273
"tests.verify(output, 'Hello World from API Management!')\n",
267274
"\n",
268275
"# 3) Successful calls to Front Door -> APIM -> ACA (200)\n",
269276
"if use_ACA:\n",
277+
" reqsAfd = ApimRequests(afd_endpoint_url, apim_apis[1]['subscriptionPrimaryKey'])\n",
270278
" output = reqsAfd.singleGet('/aca-1', msg = '3) Calling Hello World (ACA 1) API via Azure Front Door. Expect 200.')\n",
271279
" tests.verify(output, 'Hello World!')\n",
272280
"\n",
281+
" reqsAfd = ApimRequests(afd_endpoint_url, apim_apis[2]['subscriptionPrimaryKey'])\n",
273282
" output = reqsAfd.singleGet('/aca-2', msg = '4) Calling Hello World (ACA 2) API via Azure Front Door. Expect 200.')\n",
274283
" tests.verify(output, 'Hello World!')\n",
275284
"\n",
285+
" reqsAfd = ApimRequests(afd_endpoint_url, apim_apis[3]['subscriptionPrimaryKey'])\n",
276286
" output = reqsAfd.singleGet('/aca-pool', msg = '5) Calling Hello World (ACA Pool) API via Azure Front Door. Expect 200.')\n",
277287
" tests.verify(output, 'Hello World!')\n",
278288
"else:\n",
279289
" utils.print_message('ACA APIs were not created. Skipping ACA API calls.', blank_above = True)\n",
280290
"\n",
291+
"# 4) Unsuccessful call to Front Door without API subscription key (should fail with 401 Unauthorized)\n",
292+
"reqsNoApiSubscription = ApimRequests(afd_endpoint_url)\n",
293+
"output = reqsNoApiSubscription.singleGet('/', msg = 'Calling Hello World (Root) API without API subscription key. Expect 401.')\n",
294+
"outputJson = utils.get_json(output)\n",
295+
"tests.verify(outputJson['statusCode'], 401)\n",
296+
"tests.verify(outputJson['message'], 'Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API.')\n",
297+
"\n",
281298
"tests.print_summary()\n",
282299
"\n",
283300
"utils.print_ok('All done!')"

infrastructure/afd-apim-pe/main.bicep

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,5 +311,16 @@ output apimResourceGatewayURL string = apimModule.outputs.gatewayUrl
311311
output fdeHostName string = afdModule.outputs.fdeHostName
312312
output fdeSecureUrl string = afdModule.outputs.fdeSecureUrl
313313

314-
#disable-next-line outputs-should-not-contain-secrets
315-
//output apimSubscription1Key string = apimModule.outputs.[0].listSecrets().primaryKey
314+
// API outputs
315+
output apiOutputs array = [for i in range(0, length(apis)): {
316+
name: apis[i].name
317+
resourceId: apisModule[i].?outputs.?apiResourceId ?? ''
318+
displayName: apisModule[i].?outputs.?apiDisplayName ?? ''
319+
productAssociationCount: apisModule[i].?outputs.?productAssociationCount ?? 0
320+
subscriptionResourceId: apisModule[i].?outputs.?subscriptionResourceId ?? ''
321+
subscriptionName: apisModule[i].?outputs.?subscriptionName ?? ''
322+
subscriptionPrimaryKey: apisModule[i].?outputs.?subscriptionPrimaryKey ?? ''
323+
subscriptionSecondaryKey: apisModule[i].?outputs.?subscriptionSecondaryKey ?? ''
324+
}]
325+
326+
// [ADD RELEVANT OUTPUTS HERE]

infrastructure/apim-aca/create.ipynb

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,34 @@
3636
" PolicyFragment('AuthZ-Match-All', utils.read_policy_xml(utils.determine_shared_policy_path('pf-authz-match-all.xml')), 'Authorizes if all of the specified roles match the JWT role claims.'),\n",
3737
" PolicyFragment('AuthZ-Match-Any', utils.read_policy_xml(utils.determine_shared_policy_path('pf-authz-match-any.xml')), 'Authorizes if any of the specified roles match the JWT role claims.'),\n",
3838
" PolicyFragment('Http-Response-200', utils.read_policy_xml(utils.determine_shared_policy_path('pf-http-response-200.xml')), 'Returns a 200 OK response for the current HTTP method.'),\n",
39+
" PolicyFragment('Product-Match-Any', utils.read_policy_xml(utils.determine_shared_policy_path('pf-product-match-any.xml')), 'Proceeds if any of the specified products match the context product name.'),\n",
3940
" PolicyFragment('Remove-Request-Headers', utils.read_policy_xml(utils.determine_shared_policy_path('pf-remove-request-headers.xml')), 'Removes request headers from the incoming request.')\n",
4041
"]\n",
4142
"\n",
4243
"# 4) Define the APIs and their operations and policies\n",
4344
"\n",
4445
"# Policies\n",
45-
"hello_world_policy_xml = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
46-
"backend_policy_xml = utils.read_policy_xml(BACKEND_XML_POLICY_PATH)\n",
47-
"aca_backend_1_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-1')\n",
48-
"aca_backend_2_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-2')\n",
49-
"aca_backend_pool_policy_xml = backend_policy_xml.format(backend_id = 'aca-backend-pool')\n",
46+
"pol_hello_world = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
47+
"pol_backend = utils.read_policy_xml(BACKEND_XML_POLICY_PATH)\n",
48+
"pol_aca_backend_1 = pol_backend.format(backend_id = 'aca-backend-1')\n",
49+
"pol_aca_backend_2 = pol_backend.format(backend_id = 'aca-backend-2')\n",
50+
"pol_aca_backend_pool = pol_backend.format(backend_id = 'aca-backend-pool')\n",
5051
"\n",
5152
"# Hello World (Root)\n",
52-
"api_hwroot_get = GET_APIOperation('This is a GET for Hello World in the root', hello_world_policy_xml)\n",
53+
"api_hwroot_get = GET_APIOperation('This is a GET for Hello World in the root', pol_hello_world)\n",
5354
"api_hwroot = API('hello-world', 'Hello World', '', 'This is the root API for Hello World', operations = [api_hwroot_get])\n",
5455
"\n",
5556
"# Hello World (ACA Backend 1)\n",
5657
"api_hwaca_1_get = GET_APIOperation('This is a GET for Hello World on ACA Backend 1')\n",
57-
"api_hwaca_1 = API('hello-world-aca-1', 'Hello World (ACA 1)', '/aca-1', 'This is the ACA API for Backend 1', policyXml = aca_backend_1_policy_xml, operations = [api_hwaca_1_get])\n",
58+
"api_hwaca_1 = API('hello-world-aca-1', 'Hello World (ACA 1)', '/aca-1', 'This is the ACA API for Backend 1', policyXml = pol_aca_backend_1, operations = [api_hwaca_1_get])\n",
5859
"\n",
5960
"# Hello World (ACA Backend 2)\n",
6061
"api_hwaca_2_get = GET_APIOperation('This is a GET for Hello World on ACA Backend 2')\n",
61-
"api_hwaca_2 = API('hello-world-aca-2', 'Hello World (ACA 2)', '/aca-2', 'This is the ACA API for Backend 2', policyXml = aca_backend_2_policy_xml, operations = [api_hwaca_2_get])\n",
62+
"api_hwaca_2 = API('hello-world-aca-2', 'Hello World (ACA 2)', '/aca-2', 'This is the ACA API for Backend 2', policyXml = pol_aca_backend_2, operations = [api_hwaca_2_get])\n",
6263
"\n",
6364
"# Hello World (ACA Backend Pool)\n",
6465
"api_hwaca_pool_get = GET_APIOperation('This is a GET for Hello World on ACA Backend Pool')\n",
65-
"api_hwaca_pool = API('hello-world-aca-pool', 'Hello World (ACA Pool)', '/aca-pool', 'This is the ACA API for Backend Pool', policyXml = aca_backend_pool_policy_xml, operations = [api_hwaca_pool_get])\n",
66+
"api_hwaca_pool = API('hello-world-aca-pool', 'Hello World (ACA Pool)', '/aca-pool', 'This is the ACA API for Backend Pool', policyXml = pol_aca_backend_pool, operations = [api_hwaca_pool_get])\n",
6667
"\n",
6768
"# APIs Array\n",
6869
"apis: List[API] = [api_hwroot, api_hwaca_1, api_hwaca_2, api_hwaca_pool]\n",
@@ -103,9 +104,10 @@
103104
" raise SystemExit('Deployment failed')\n",
104105
"\n",
105106
"if output.success and output.json_data:\n",
106-
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
107-
" aca_url_1 = output.get('acaUrl1', 'ACA Backend 1 URL')\n",
108-
" aca_url_2 = output.get('acaUrl2', 'ACA Backend 2 URL')\n",
107+
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
108+
" aca_url_1 = output.get('acaUrl1', 'ACA Backend 1 URL')\n",
109+
" aca_url_2 = output.get('acaUrl2', 'ACA Backend 2 URL')\n",
110+
" apim_apis = output.getJson('apiOutputs', 'APIs')\n",
109111
"\n",
110112
"utils.print_ok('Deployment completed')"
111113
]
@@ -129,24 +131,33 @@
129131
"from apimrequests import ApimRequests\n",
130132
"from apimtesting import ApimTesting\n",
131133
"\n",
132-
"reqs = ApimRequests(apim_gateway_url)\n",
133134
"tests = ApimTesting(\"APIM-ACA Tests\", deployment, deployment)\n",
134135
"\n",
136+
"reqs = ApimRequests(apim_gateway_url, apim_apis[0]['subscriptionPrimaryKey'])\n",
135137
"output = reqs.singleGet('/', msg = 'Calling Hello World (Root) API')\n",
136138
"tests.verify(output, 'Hello World from API Management!')\n",
137139
"\n",
140+
"reqs = ApimRequests(apim_gateway_url, apim_apis[1]['subscriptionPrimaryKey'])\n",
138141
"output = reqs.singleGet('/aca-1/', msg = 'Calling Hello World (ACA Backend 1) API')\n",
139142
"tests.verify(output, 'Hello World!')\n",
140143
"\n",
144+
"reqs = ApimRequests(apim_gateway_url, apim_apis[2]['subscriptionPrimaryKey'])\n",
141145
"output = reqs.singleGet('/aca-2/', msg = 'Calling Hello World (ACA Backend 2) API')\n",
142146
"tests.verify(output, 'Hello World!')\n",
143147
"\n",
148+
"reqs = ApimRequests(apim_gateway_url, apim_apis[3]['subscriptionPrimaryKey'])\n",
144149
"output = reqs.multiGet('/aca-pool/', 3, msg = 'Calling Hello World (ACA Backend Pool) API')\n",
145150
"tests.verify(len(output), 3)\n",
146151
"tests.verify(output[0]['response'], 'Hello World!')\n",
147152
"tests.verify(output[1]['response'], 'Hello World!')\n",
148153
"tests.verify(output[2]['response'], 'Hello World!')\n",
149154
"\n",
155+
"reqsNoApiSubscription = ApimRequests(apim_gateway_url)\n",
156+
"output = reqsNoApiSubscription.singleGet('/', msg = 'Calling Hello World (Root) API without API subscription key. Expect 401.')\n",
157+
"outputJson = utils.get_json(output)\n",
158+
"tests.verify(outputJson['statusCode'], 401)\n",
159+
"tests.verify(outputJson['message'], 'Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API.')\n",
160+
"\n",
150161
"tests.print_summary()\n",
151162
"\n",
152163
"utils.print_ok('All done!')"

infrastructure/apim-aca/main.bicep

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,17 @@ output apimServiceName string = apimModule.outputs.name
181181
output apimResourceGatewayURL string = apimModule.outputs.gatewayUrl
182182
output acaUrl1 string = 'https://${acaModule1.outputs.containerAppFqdn}'
183183
output acaUrl2 string = 'https://${acaModule2.outputs.containerAppFqdn}'
184+
185+
// API outputs
186+
output apiOutputs array = [for i in range(0, length(apis)): {
187+
name: apis[i].name
188+
resourceId: apisModule[i].?outputs.?apiResourceId ?? ''
189+
displayName: apisModule[i].?outputs.?apiDisplayName ?? ''
190+
productAssociationCount: apisModule[i].?outputs.?productAssociationCount ?? 0
191+
subscriptionResourceId: apisModule[i].?outputs.?subscriptionResourceId ?? ''
192+
subscriptionName: apisModule[i].?outputs.?subscriptionName ?? ''
193+
subscriptionPrimaryKey: apisModule[i].?outputs.?subscriptionPrimaryKey ?? ''
194+
subscriptionSecondaryKey: apisModule[i].?outputs.?subscriptionSecondaryKey ?? ''
195+
}]
196+
197+
// [ADD RELEVANT OUTPUTS HERE]

0 commit comments

Comments
 (0)