Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3bdfa1c
Add Azure Maps integration with APIM, including policies and Bicep co…
anotherRedbeard Jun 12, 2025
3879831
Enhance Azure Maps integration by implementing user-assigned managed …
anotherRedbeard Jun 17, 2025
5feb2c1
Merge branch 'main' into ar/azure-maps
simonkurtz-MSFT Jun 17, 2025
a6cf6e3
Fix policy XML read
simonkurtz-MSFT Jun 17, 2025
cc146c4
Update Azure Maps sample documentation and enhance async request hand…
anotherRedbeard Jun 18, 2025
7fd2671
Merge branch 'ar/azure-maps' of https://github.com/Azure-Samples/Apim…
anotherRedbeard Jun 18, 2025
b191db1
Add Azure Maps integration with APIM, including policies and Bicep co…
anotherRedbeard Jun 12, 2025
816abf8
Enhance Azure Maps integration by implementing user-assigned managed …
anotherRedbeard Jun 17, 2025
8d3c32a
Update Azure Maps sample documentation and enhance async request hand…
anotherRedbeard Jun 18, 2025
c62e458
Fix policy XML read
simonkurtz-MSFT Jun 17, 2025
4a5a829
wqMerge branch 'ar/azure-maps' of https://github.com/Azure-Samples/Ap…
anotherRedbeard Jun 18, 2025
79d4d85
Enhance Azure Maps sample notebook and Bicep templates
anotherRedbeard Jun 18, 2025
5a611bd
Remove output logs from Azure Maps sample notebook to streamline exec…
anotherRedbeard Jun 18, 2025
0637718
Add Azure Maps integration with APIM, including policies and Bicep co…
anotherRedbeard Jun 12, 2025
66b93f7
Enhance Azure Maps integration by implementing user-assigned managed …
anotherRedbeard Jun 17, 2025
eeb36f8
Update Azure Maps sample documentation and enhance async request hand…
anotherRedbeard Jun 18, 2025
fb8c244
Fix policy XML read
simonkurtz-MSFT Jun 17, 2025
a3c23ec
Enhance Azure Maps sample notebook and Bicep templates
anotherRedbeard Jun 18, 2025
8c1b9ad
Remove output logs from Azure Maps sample notebook to streamline exec…
anotherRedbeard Jun 18, 2025
dba0707
Merge branch 'ar/azure-maps' of https://github.com/Azure-Samples/Apim…
anotherRedbeard Jun 18, 2025
7c026fa
Refactor Azure Maps sample notebook and Bicep templates for improved …
anotherRedbeard Jun 18, 2025
7232be5
Merge branch 'main' into ar/azure-maps
anotherRedbeard Jun 18, 2025
b88cacf
Fix function call for Bicep deployment in Azure Maps sample notebook
anotherRedbeard Jun 18, 2025
93ef931
Enhance Azure Maps sample notebook and Bicep templates with improved …
anotherRedbeard Jun 19, 2025
61b4f12
Merge branch 'main' into ar/azure-maps
simonkurtz-MSFT Jun 19, 2025
80e47b8
Update README.md to enhance Azure Maps sample documentation with deta…
anotherRedbeard Jun 19, 2025
2f939c9
Add refactoring changes
simonkurtz-MSFT Jun 19, 2025
26f947f
Update test initialization and add preflight check for Azure Maps sample
anotherRedbeard Jun 19, 2025
5b39ce5
Use the determined endpoint URL in tests
simonkurtz-MSFT Jun 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ For detailed troubleshooting of setup issues, see [Import Troubleshooting Guide]
| [Load Balancing](./samples/load-balancing/README.md) | Priority and weighted load balancing across backends. | apim-aca, afd-apim (with ACA) |
| [Secure Blob Access](./samples/secure-blob-access/README.md) | Secure blob access via the [valet key pattern](https://learn.microsoft.com/azure/architecture/patterns/valet-key). | All infrastructures |
| [Credential Manager (with Spotify)](./samples/oauth-3rd-party/README.md) | Authenticate with APIM which then uses its Credential Manager with Spotify's REST API. | All infrastructures |
| [Azure Maps](./samples/azure-maps/README.md) | Proxying calls to Azure Maps with APIM policies. | All infrastructures |

### ▶️ Running a Sample

Expand Down
37 changes: 37 additions & 0 deletions samples/azure-maps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Samples: Api Management proxing calls to Azure Maps

This is a sample demonstrating how to use Azure API Management (APIM) to proxy calls to the Azure Maps service. This setup allows you to manage, secure, and monitor access to Azure Maps through APIM.
Comment thread
simonkurtz-MSFT marked this conversation as resolved.
Outdated

⚙️ **Supported infrastructures**: All infrastructures

👟 **Expected *Run All* runtime (excl. infrastructure prerequisite): ~[NOTEBOOK RUNTIME] minute**

## 🎯 Objectives

1. Learn how to set up APIM to proxy requests to Azure Maps on a path to operation based mapping.
1. Learn how to set up APIM to proxy requests to Azure Maps on a generic path.
1. See how to secure access to Azure Maps using APIM policies for all 3 authentication methods (subscription key, Azure Entra AD, and SAS Tokens).
1. Show how to connect to the v1 enpoint of Azure Maps using APIM.

## 📝 Scenario

This sample demonstrates how to use APIM to proxy requests to the Azure Maps service. By doing so, you can leverage APIM's capabilities to manage, secure, and monitor access to Azure Maps. This particular setup will show you how to map specific paths to Azure Maps APIs, as well as how to handle generic paths. Additionally, the sample will illustrate how to secure access to Azure Maps using different authentication methods supported by APIM policies.

## 🛩️ Lab Components

This lab sets up:

- An Azure Maps resource in Azure
- APIM managed identity with the following roles:
- **Azure Maps Search and Render Data Reader:** Grants the ability to call the apis and render the maps
- **Azure Maps Contributor:** Grants the ability to create the SAS Token from the APIM policy
- A User Assigned Managed Identity (UAMI) that is used as the principal id to emulate when creating the SAS Token for Azure Maps. It has the following roles asigned:
- **Azure Maps Search and Render Data Reader:** Grants the ability to call the apis and render the maps
- An API that demonstrates proxying requests to Azure Maps specific to APIs (geocode, search, etc.)
- Also in that api there will be an operation that demonstrates a generic path to Azure Maps

## ⚙️ Configuration

1. Decide which of the [Infrastructure Architectures](../../README.md#infrastructure-architectures) you wish to use.
1. If the infrastructure _does not_ yet exist, navigate to the desired [infrastructure](../../infrastructure/) folder and follow its README.md.
1. If the infrastructure _does_ exist, adjust the `user-defined parameters` in the _Initialize notebook variables_ below. Please ensure that all parameters match your infrastructure.
166 changes: 166 additions & 0 deletions samples/azure-maps/create.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 🛠️ 1. Initialize notebook variables\n",
"\n",
"Configures everything that's needed for deployment. \n",
"\n",
"**Modify entries under _1) User-defined parameters_ and _3) Define the APIs and their operations and policies_**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import utils\n",
"from apimtypes import *\n",
"\n",
"# 1) User-defined parameters (change these as needed)\n",
"rg_location = 'eastus2'\n",
"index = 1\n",
"deployment = INFRASTRUCTURE.SIMPLE_APIM\n",
"tags = ['azure-maps'] # ENTER DESCRIPTIVE TAG(S)\n",
"api_prefix = 'am-' # OPTIONAL: ENTER A PREFIX FOR THE APIS TO REDUCE COLLISION POTENTIAL WITH OTHER SAMPLES\n",
"azure_maps_url = 'https://atlas.microsoft.com' # OPTIONAL: ENTER THE AZURE MAPS URL IF DIFFERENT FROM DEFAULT\n",
Comment thread
simonkurtz-MSFT marked this conversation as resolved.
"\n",
"# 2) Service-defined parameters (please do not change these)\n",
"rg_name = utils.get_infra_rg_name(deployment, index)\n",
"supported_infrastructures = [INFRASTRUCTURE.SIMPLE_APIM, INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.APIM_ACA] # ENTER SUPPORTED INFRASTRUCTURES HERE, e.g., [INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.AFD_APIM_FE]\n",
"utils.validate_infrastructure(deployment, supported_infrastructures)\n",
"sample_folder = \"azure-maps\"\n",
"# 3) Define the APIs and their operations and policies\n",
"\n",
"# Policies\n",
"# Named values must be set up a bit differently as they need to have two surrounding curly braces\n",
"map_async_geocode_batch_v1_keyauth_post_xml = utils.read_policy_xml('map_async_geocode_batch_v1_keyauth_post.xml', sample_name=sample_folder)\n",
"map_default_route_v2_aad_get_xml = utils.read_policy_xml('map_default_route_v2_aad_get.xml', sample_name=sample_folder)\n",
"map_geocode_v2_aad_get_xml = utils.read_policy_xml('map_geocode_v2_aad_get.xml', sample_name=sample_folder)\n",
"\n",
"# Map API \n",
"mapApi_v2_default_get = GET_APIOperation2('get-default-route','Get default route','/default/*','This is the default route that will allow all requests to go through to the backend api',map_default_route_v2_aad_get_xml)\n",
"mapApi_v1_async_post = APIOperation('async-geocode-batch','Async Geocode Batch','/geocode/batch/async',HTTP_VERB.POST, 'Post geocode batch async endpoint',map_async_geocode_batch_v1_keyauth_post_xml)\n",
"mapApi_v2_geocode_get = GET_APIOperation2('get-geocode','Get Geocode','/geocode','Get geocode endpoint',map_geocode_v2_aad_get_xml)\n",
"api1 = API('map-api', 'Map API', '/map', 'This is the proxy for Azure Maps', operations=[mapApi_v2_default_get, mapApi_v1_async_post,mapApi_v2_geocode_get], tags = tags, serviceUrl=azure_maps_url)\n",
"\n",
"# APIs Array\n",
"# apis: List[API] = [api1, apin]\n",
"apis: List[API] = [api1]\n",
"\n",
"# 4) Set up the named values, for this specific sample, we are using some of the named values in the API policies defined above that can't be known at this point in the process. For those named values, we are setting them in the main.bicep file.\n",
"nvs: List[NamedValue] = [\n",
" NamedValue('azure-maps-arm-api-version','2023-06-01')\n",
"]\n",
"\n",
"utils.print_ok('Notebook initialized')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 🚀 2. Create deployment using Bicep\n",
"\n",
"Creates the bicep deployment into the previously-specified resource group. A bicep parameters file will be created prior to execution."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import utils\n",
"\n",
"# 1) Define the Bicep parameters with serialized APIs\n",
"bicep_parameters = {\n",
" 'apis': {'value': [api.to_dict() for api in apis]},\n",
" 'namedValues': {'value': [nv.to_dict() for nv in nvs]}\n",
"}\n",
"\n",
"# 2) Infrastructure must be in place before samples can be layered on top\n",
"if not utils.does_resource_group_exist(rg_name):\n",
" utils.print_error(f'The specified infrastructure resource group and its resources must exist first. Please check that the user-defined parameters above are correctly referencing an existing infrastructure. If it does not yet exist, run the desired infrastructure in the /infra/ folder first.')\n",
" raise SystemExit(1)\n",
"\n",
"# 3) Run the deployment\n",
"output = utils.create_bicep_deployment_group_for_sample(sample_folder, rg_name, rg_location, bicep_parameters)\n",
"\n",
"# 4) Print a deployment summary, if successful; otherwise, exit with an error\n",
"if not output.success:\n",
" raise SystemExit('Deployment failed')\n",
"\n",
"if output.success and output.json_data:\n",
" apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n",
"\n",
"utils.print_ok('Deployment completed')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ✅ 3. Verify API Request Success\n",
"\n",
"Assert that the deployment was successful by making simple calls to APIM. \n",
"\n",
"❗️ If the infrastructure shields APIM and requires a different ingress (e.g. Azure Front Door), the request to the APIM gateway URl will fail by design. Obtain the Front Door endpoint hostname and try that instead."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import utils\n",
"from apimrequests import ApimRequests\n",
"\n",
"reqs = ApimRequests(apim_gateway_url)\n",
"\n",
"# 1) Issue a direct request to API Management\n",
Comment thread
simonkurtz-MSFT marked this conversation as resolved.
"reqs.singleGet('/', msg = 'Calling Hello World (Root) API. Expect 200.')\n",
"\n",
"# 2) Issue requests to API Management with Azure Maps APIs\n",
"reqs.singleGet('/map/default/geocode?query=15127%20NE%2024th%20Street%20Redmond%20WA', msg = 'Calling Default Route API with SAS Token Auth. Expect 200.')\n",
"reqs.singleGet('/map/geocode?query=15127%20NE%2024th%20Street%20Redmond%20WA', msg = 'Calling Geocode v2 API with AAD Auth. Expect 200.')\n",
"reqs.singlePostAsync('/map/geocode/batch/async', data={\n",
" \"batchItems\": [\n",
" {\"query\": \"?query=400 Broad St, Seattle, WA 98109&limit=3\"},\n",
" {\"query\": \"?query=One, Microsoft Way, Redmond, WA 98052&limit=3\"},\n",
" {\"query\": \"?query=350 5th Ave, New York, NY 10118&limit=1\"},\n",
" {\"query\": \"?query=Pike Pl, Seattle, WA 98101&lat=47.610970&lon=-122.342469&radius=1000\"},\n",
" {\"query\": \"?query=Champ de Mars, 5 Avenue Anatole France, 75007 Paris, France&limit=1\"}\n",
" ]\n",
"}, msg = 'Calling Async Geocode Batch v1 API with Share Key Auth. Expect initial 202, then a 200 on the polling response', timeout=120, poll_interval=3)\n",
"\n",
"utils.print_ok('All done!')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.11"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading