Skip to content

Commit 6870d9c

Browse files
Feature/move shared policy fragments (#59)
1 parent 513f675 commit 6870d9c

File tree

10 files changed

+102
-31
lines changed

10 files changed

+102
-31
lines changed

infrastructure/afd-apim-pe/create.ipynb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@
3232
"rg_tags = utils.build_infrastructure_tags(deployment)\n",
3333
"apim_network_mode = APIMNetworkMode.EXTERNAL_VNET\n",
3434
"\n",
35-
"# 3) Define the APIs and their operations and policies\n",
35+
"# 3) Set up the policy fragments\n",
36+
"pfs: List[PolicyFragment] = [\n",
37+
" 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",
38+
" 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",
39+
" 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",
40+
" 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",
41+
"]\n",
42+
"\n",
43+
"# 4) Define the APIs and their operations and policies\n",
3644
"\n",
3745
"# Policies\n",
3846
"hello_world_policy_xml = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
@@ -92,6 +100,7 @@
92100
"bicep_parameters = {\n",
93101
" 'apimSku' : {'value': apim_sku.value},\n",
94102
" 'apis' : {'value': [api.to_dict() for api in apis]},\n",
103+
" 'policyFragments' : {'value': [pf.to_dict() for pf in pfs]},\n",
95104
" 'apimPublicAccess' : {'value': apim_network_mode in [APIMNetworkMode.PUBLIC, APIMNetworkMode.EXTERNAL_VNET]},\n",
96105
" 'useACA' : {'value': use_ACA}\n",
97106
"}\n",

infrastructure/afd-apim-pe/main.bicep

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ param acaSubnetPrefix string = '10.0.2.0/23'
2727
param apimName string = 'apim-${resourceSuffix}'
2828
param apimSku string
2929
param apis array = []
30+
param policyFragments array = []
3031

3132
@description('Set to true to make APIM publicly accessible. If false, APIM will be deployed into a VNet subnet for egress only.')
3233
param apimPublicAccess bool = true
@@ -175,7 +176,21 @@ module apimModule '../../shared/bicep/modules/apim/v1/apim.bicep' = {
175176
]
176177
}
177178

178-
// 7. APIM Backends for ACA
179+
// 7. APIM Policy Fragments
180+
module policyFragmentModule '../../shared/bicep/modules/apim/v1/policy-fragment.bicep' = [for pf in policyFragments: {
181+
name: 'pf-${pf.name}'
182+
params:{
183+
apimName: apimName
184+
policyFragmentName: pf.name
185+
policyFragmentDescription: pf.description
186+
policyFragmentValue: pf.policyXml
187+
}
188+
dependsOn: [
189+
apimModule
190+
]
191+
}]
192+
193+
// 8. APIM Backends for ACA
179194
module backendModule1 '../../shared/bicep/modules/apim/v1/backend.bicep' = if (useACA) {
180195
name: 'aca-backend-1'
181196
params: {
@@ -224,7 +239,7 @@ module backendPoolModule '../../shared/bicep/modules/apim/v1/backend-pool.bicep'
224239
]
225240
}
226241

227-
// 8. APIM APIs
242+
// 9. APIM APIs
228243
module apisModule '../../shared/bicep/modules/apim/v1/api.bicep' = [for api in apis: if(length(apis) > 0) {
229244
name: 'api-${api.name}'
230245
params: {
@@ -241,7 +256,7 @@ module apisModule '../../shared/bicep/modules/apim/v1/api.bicep' = [for api in a
241256
]
242257
}]
243258

244-
// 9. APIM Private DNS Zone, VNet Link, and (optional) DNS Zone Group
259+
// 10. APIM Private DNS Zone, VNet Link, and (optional) DNS Zone Group
245260
module apimDnsPrivateLinkModule '../../shared/bicep/modules/dns/v1/dns-private-link.bicep' = {
246261
name: 'apimDnsPrivateLinkModule'
247262
params: {
@@ -254,7 +269,7 @@ module apimDnsPrivateLinkModule '../../shared/bicep/modules/dns/v1/dns-private-l
254269
}
255270
}
256271

257-
// 10. ACA Private DNS Zone (regional, e.g., eastus2.azurecontainerapps.io), VNet Link, and wildcard A record via shared module
272+
// 11. ACA Private DNS Zone (regional, e.g., eastus2.azurecontainerapps.io), VNet Link, and wildcard A record via shared module
258273
module acaDnsPrivateZoneModule '../../shared/bicep/modules/dns/v1/aca-dns-private-zone.bicep' = if (useACA && !empty(acaSubnetResourceId)) {
259274
name: 'acaDnsPrivateZoneModule'
260275
params: {
@@ -264,7 +279,7 @@ module acaDnsPrivateZoneModule '../../shared/bicep/modules/dns/v1/aca-dns-privat
264279
}
265280
}
266281

267-
// 11. Front Door
282+
// 12. Front Door
268283
module afdModule '../../shared/bicep/modules/afd/v1/afd.bicep' = {
269284
name: 'afdModule'
270285
params: {

infrastructure/apim-aca/create.ipynb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@
3030
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
3131
"rg_tags = utils.build_infrastructure_tags(deployment)\n",
3232
"\n",
33-
"# 3) Define the APIs and their operations and policies\n",
33+
"# 3) Set up the policy fragments\n",
34+
"pfs: List[PolicyFragment] = [\n",
35+
" 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",
36+
" 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",
37+
" 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",
38+
" 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",
39+
"]\n",
40+
"\n",
41+
"# 4) Define the APIs and their operations and policies\n",
3442
"\n",
3543
"# Policies\n",
3644
"hello_world_policy_xml = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
@@ -81,7 +89,8 @@
8189
"# 1) Define the Bicep parameters with serialized APIs\n",
8290
"bicep_parameters = {\n",
8391
" 'apimSku' : {'value': apim_sku.value},\n",
84-
" 'apis' : {'value': [api.to_dict() for api in apis]}\n",
92+
" 'apis' : {'value': [api.to_dict() for api in apis]},\n",
93+
" 'policyFragments': {'value': [pf.to_dict() for pf in pfs]}\n",
8594
"}\n",
8695
"\n",
8796
"# 2) Run the deployment\n",

infrastructure/apim-aca/main.bicep

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ param resourceSuffix string = uniqueString(subscription().id, resourceGroup().id
1111
param apimName string = 'apim-${resourceSuffix}'
1212
param apimSku string
1313
param apis array = []
14+
param policyFragments array = []
1415

1516

1617
// ------------------
@@ -82,7 +83,21 @@ module apimModule '../../shared/bicep/modules/apim/v1/apim.bicep' = {
8283
}
8384
}
8485

85-
// 6. APIM Backends for ACA
86+
// 6. APIM Policy Fragments
87+
module policyFragmentModule '../../shared/bicep/modules/apim/v1/policy-fragment.bicep' = [for pf in policyFragments: {
88+
name: 'pf-${pf.name}'
89+
params:{
90+
apimName: apimName
91+
policyFragmentName: pf.name
92+
policyFragmentDescription: pf.description
93+
policyFragmentValue: pf.policyXml
94+
}
95+
dependsOn: [
96+
apimModule
97+
]
98+
}]
99+
100+
// 7. APIM Backends for ACA
86101
module backendModule1 '../../shared/bicep/modules/apim/v1/backend.bicep' = {
87102
name: 'aca-backend-1'
88103
params: {

infrastructure/simple-apim/create.ipynb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@
3030
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
3131
"rg_tags = utils.build_infrastructure_tags(deployment)\n",
3232
"\n",
33-
"# 3) Define the APIs and their operations and policies\n",
33+
"# 3) Set up the policy fragments\n",
34+
"pfs: List[PolicyFragment] = [\n",
35+
" 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",
36+
" 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",
37+
" 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",
38+
" 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",
39+
"]\n",
40+
"\n",
41+
"# 4) Define the APIs and their operations and policies\n",
3442
"\n",
3543
"# Policies\n",
3644
"hello_world_policy_xml = utils.read_policy_xml(HELLO_WORLD_XML_POLICY_PATH)\n",
@@ -65,7 +73,8 @@
6573
"# 1) Define the Bicep parameters with serialized APIs\n",
6674
"bicep_parameters = {\n",
6775
" 'apimSku' : {'value': apim_sku.value},\n",
68-
" 'apis' : {'value': [api.to_dict() for api in apis]}\n",
76+
" 'apis' : {'value': [api.to_dict() for api in apis]},\n",
77+
" 'policyFragments': {'value': [pf.to_dict() for pf in pfs]}\n",
6978
"}\n",
7079
"\n",
7180
"# 2) Run the deployment\n",

infrastructure/simple-apim/main.bicep

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ param apimName string = 'apim-${resourceSuffix}'
1212

1313
param apimSku string
1414
param apis array = []
15-
15+
param policyFragments array = []
1616

1717
// ------------------
1818
// RESOURCES
@@ -47,7 +47,21 @@ module apimModule '../../shared/bicep/modules/apim/v1/apim.bicep' = {
4747
}
4848
}
4949

50-
// 4. APIM APIs
50+
// 4. APIM Policy Fragments
51+
module policyFragmentModule '../../shared/bicep/modules/apim/v1/policy-fragment.bicep' = [for pf in policyFragments: {
52+
name: 'pf-${pf.name}'
53+
params:{
54+
apimName: apimName
55+
policyFragmentName: pf.name
56+
policyFragmentDescription: pf.description
57+
policyFragmentValue: pf.policyXml
58+
}
59+
dependsOn: [
60+
apimModule
61+
]
62+
}]
63+
64+
// 5. APIM APIs
5165
module apisModule '../../shared/bicep/modules/apim/v1/api.bicep' = [for api in apis: if(length(apis) > 0) {
5266
name: 'api-${api.name}'
5367
params: {

samples/authX-pro/create.ipynb

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,8 @@
5454
" 'hr_member_role_id': 'HRMemberRoleId'\n",
5555
"}, sample_folder)\n",
5656
"\n",
57-
"# TODO: These shared policies may be better applied as part of each infrastructure deployments. \n",
58-
"from apimtypes import _get_project_root\n",
59-
"project_root = _get_project_root()\n",
60-
"pf_authz_match_any_xml = utils.read_policy_xml(str(project_root / 'shared' / 'apim-policies' / 'fragments' / 'pf-authz-match-any.xml'))\n",
61-
"pf_http_response_200_xml = utils.read_policy_xml(str(project_root / 'shared' / 'apim-policies' / 'fragments' / 'pf-http-response-200.xml'))\n",
62-
"\n",
6357
"pfs: List[PolicyFragment] = [\n",
64-
" PolicyFragment('AuthX-HR-Member', pf_authx_hr_member_xml, 'Authenticates and authorizes HR members.'),\n",
65-
" PolicyFragment('AuthZ-Match-Any', pf_authz_match_any_xml, 'Authorizes if any of the specified roles match the JWT role claims.'),\n",
66-
" PolicyFragment('Http-Response-200', pf_http_response_200_xml, 'Returns a 200 OK response for the current HTTP method.')\n",
58+
" PolicyFragment('AuthX-HR-Member', pf_authx_hr_member_xml, 'Authenticates and authorizes HR members.')\n",
6759
"]\n",
6860
"\n",
6961
"# 5) Define the Products\n",

samples/secure-blob-access/create.ipynb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,9 @@
5656
"\n",
5757
"pf_create_sas_token_xml = utils.read_policy_xml('pf-create-sas-token.xml', sample_name = sample_folder)\n",
5858
"pf_check_blob_existence_via_mi = utils.read_policy_xml('pf-check-blob-existence-via-managed-identity.xml', sample_name = sample_folder)\n",
59-
"# TODO: These shared policies may be better applied as part of each infrastructure deployments. \n",
60-
"from apimtypes import _get_project_root\n",
61-
"project_root = _get_project_root()\n",
62-
"pf_authz_match_any_xml = utils.read_policy_xml(str(project_root / 'shared' / 'apim-policies' / 'fragments' / 'pf-authz-match-any.xml'))\n",
6359
"\n",
6460
"pfs: List[PolicyFragment] = [\n",
6561
" PolicyFragment('AuthX-HR-Member', pf_authx_hr_member_xml, 'Authenticates and authorizes users with HR Member role.'),\n",
66-
" PolicyFragment('AuthZ-Match-Any', pf_authz_match_any_xml, 'Authorizes if any of the specified roles match the JWT role claims.'),\n",
6762
" PolicyFragment('Create-Sas-Token', pf_create_sas_token_xml, 'Creates a SAS token to use with access to a blob.'),\n",
6863
" PolicyFragment('Check-Blob-Existence-via-Managed-Identity', pf_check_blob_existence_via_mi, 'Checks whether the specified blob exists at the blobUrl. A boolean value for blobExists will be available afterwards.')\n",
6964
"]\n",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!--
2+
- This fragment removes incoming request headers prior to calling a backend or external service.
3+
-->
4+
<fragment>
5+
<!-- Remove APIM API keys to not inadvertently leak them. -->
6+
<set-header name="api-key" exists-action="delete" />
7+
<set-header name="ocp-apim-subscription-key" exists-action="delete" />
8+
9+
<!-- The Do Not Track (DNT) header is deprecated: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/DNT -->
10+
<set-header name="DNT" exists-action="delete" />
11+
</fragment>

shared/python/utils.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import string
1414
import secrets
1515
import base64
16+
import inspect
17+
from pathlib import Path
1618

1719
from typing import Optional, Tuple
1820
from apimtypes import APIM_SKU, HTTP_VERB, INFRASTRUCTURE
@@ -418,6 +420,7 @@ def create_bicep_deployment_group(rg_name: str, rg_location: str, deployment: st
418420
f"Deployment '{deployment_name}' succeeded", f"Deployment '{deployment_name}' failed.")
419421

420422

423+
# TODO: Reconcile this with apimtypes.py _get_project_root
421424
def find_project_root() -> str:
422425
"""
423426
Find the project root directory by looking for specific marker files.
@@ -573,11 +576,10 @@ def read_and_modify_policy_xml(policy_xml_filepath: str, replacements: dict[str,
573576

574577
return policy_template_xml
575578

579+
def determine_shared_policy_path(policy_xml_filename: str) -> str:
580+
return str(Path(find_project_root()) / 'shared' / 'apim-policies' / 'fragments' / policy_xml_filename)
581+
576582
def determine_policy_path(policy_xml_filepath_or_filename: str, sample_name: str = None) -> str:
577-
import inspect
578-
import os
579-
from pathlib import Path
580-
581583
# Determine if this is a full path or just a filename
582584
path_obj = Path(policy_xml_filepath_or_filename)
583585

0 commit comments

Comments
 (0)