Skip to content

Commit 7b52af3

Browse files
Add App Gateway Private Endpoint to APIM infrastructure (#99) (#100)
1 parent 4119e86 commit 7b52af3

28 files changed

+1885
-324
lines changed

.vscode/settings.json

Lines changed: 20 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,28 @@
11
{
2-
// Whitespace and formatting
2+
"jupyter.defaultKernel": "apim-samples",
3+
"jupyter.kernels.changeKernelIdForNotebookEnabled": false,
4+
"jupyter.preferredKernelIdForNotebook": {
5+
"*.ipynb": "apim-samples"
6+
},
7+
"jupyter.kernels.trusted": [
8+
"./.venv/Scripts/python.exe"
9+
],
10+
"jupyter.kernels.excludePythonEnvironments": [
11+
"apim-samples"
12+
],
313
"files.trimTrailingWhitespace": true,
414
"files.insertFinalNewline": true,
515
"files.trimFinalNewlines": true,
616
"editor.renderWhitespace": "trailing",
7-
8-
// PlantUML
9-
"plantuml.diagramsRoot": "assets/diagrams/src",
17+
"python.defaultInterpreterPath": "./.venv/Scripts/python.exe",
18+
"python.pythonPath": "./.venv/Scripts/python.exe",
19+
"python.envFile": "${workspaceFolder}/.env",
20+
"notebook.defaultLanguage": "python",
21+
"notebook.kernelPickerType": "mru",
22+
"terminal.integrated.defaultProfile.windows": "PowerShell",
23+
"plantuml.render": "Local",
1024
"plantuml.exportFormat": "svg",
11-
"plantuml.exportOutDir": "assets/diagrams/out",
1225
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
13-
"plantuml.render": "Local",
14-
"python.analysis.autoIndent": true,
15-
"python.analysis.completeFunctionParens": true,
16-
"python.analysis.diagnosticSeverityOverrides": {
17-
"reportDuplicateImport": "warning",
18-
"reportUndefinedVariable": "information",
19-
"reportUnusedVariable": "information"
20-
},
21-
"python.analysis.extraPaths": [
22-
"${workspaceFolder}/shared/python"
23-
],
24-
"python.defaultInterpreterPath": "/workspaces/Apim-Samples/.venv/bin/python",
25-
"python.pythonPath": "/workspaces/Apim-Samples/.venv/bin/python",
26-
"python.envFile": "${workspaceFolder}/.env",
27-
"python.terminal.activateEnvironment": true,
28-
"python.terminal.activateEnvInCurrentTerminal": true,
29-
"jupyter.askForKernelRestart": false,
30-
"jupyter.interactiveWindow.textEditor.executeSelection": true,
31-
"jupyter.notebookFileRoot": "${workspaceFolder}",
32-
"jupyter.kernels.excludePythonEnvironments": [
33-
"**/anaconda3/**",
34-
"**/conda/**",
35-
"**/miniconda3/**",
36-
"**/python3.*",
37-
"*/site-packages/*",
38-
"/bin/python",
39-
"/bin/python3",
40-
"/opt/python/*/bin/python*",
41-
"/usr/bin/python",
42-
"/usr/bin/python3",
43-
"/usr/local/bin/python",
44-
"/usr/local/bin/python3",
45-
"python",
46-
"python3"
47-
],
48-
"jupyter.kernels.trusted": [
49-
"/workspaces/Apim-Samples/.venv/bin/python"
50-
],
51-
"terminal.integrated.env.windows": {
52-
"PATH": "${env:PATH}"
53-
},
54-
"terminal.integrated.showExitAlert": false,
55-
"terminal.integrated.focusAfterRun": "terminal",
56-
"terminal.integrated.defaultProfile.linux": "bash",
57-
"workbench.panel.defaultLocation": "bottom",
58-
"workbench.startupEditor": "none",
59-
"workbench.panel.defaultPanelHeight": 350,
60-
"workbench.view.alwaysShowHeaderActions": true,
61-
"terminal.integrated.tabs.enabled": true,
62-
"terminal.integrated.tabs.location": "left",
63-
"xml.validation.enabled": false,
64-
"xml.validation.namespaces.enabled": "never",
65-
"xml.validation.schema.enabled": "never",
66-
"xml.validation.disallowDocTypeDecl": false,
67-
"xml.validation.resolveExternalEntities": false,
68-
"xml.format.enabled": false,
69-
"xml.format.emptyElements": "ignore",
70-
"xml.format.enforceQuoteStyle": "preferred",
71-
"xml.format.preserveEmptyContent": true,
72-
"xml.format.preserveSpace": [
73-
"xsl:text",
74-
"xsl:comment",
75-
"xsl:processing-instruction",
76-
"literal",
77-
"xsl:preserve-space",
78-
"fragment",
79-
"condition"
80-
],
81-
"xml.format.splitAttributes": "preserve",
82-
"xml.format.joinCDATALines": false,
83-
"xml.format.joinCommentLines": false,
84-
"xml.format.joinContentLines": false,
85-
"xml.format.spaceBeforeEmptyCloseTag": true,
86-
"xml.format.xsiSchemaLocationSplit": "onPair",
87-
"xml.completion.autoCloseTags": true,
88-
"xml.codeLens.enabled": false,
89-
"xml.preferences.includeSchemaAssociations": "never",
90-
"xml.trace.server": "off",
91-
"files.associations": {
92-
"*.xml": "xml",
93-
"**/apim-policies/*.xml": "xml",
94-
"**/samples/**/*.xml": "xml",
95-
"pf-*.xml": "xml",
96-
"hr_*.xml": "xml"
97-
},
98-
"html.validate": false,
99-
"azureApiManagement.policies.validateSyntax": true,
100-
"azureApiManagement.policies.showCodeLens": true,
101-
"[xml]": {
102-
"editor.quickSuggestions": {
103-
"other": true,
104-
"comments": false,
105-
"strings": true
106-
},
107-
"editor.autoClosingBrackets": "always",
108-
"editor.autoClosingQuotes": "always",
109-
"editor.suggest.insertMode": "replace",
110-
"editor.formatOnSave": false,
111-
"editor.formatOnPaste": false,
112-
"editor.formatOnType": false
113-
}
26+
"plantuml.diagramsRoot": "assets/diagrams/src",
27+
"plantuml.exportOutDir": "assets/diagrams/out"
11428
}

README.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/11057/badge)](https://www.bestpractices.dev/projects/11057)
44
[![Python Tests][badge-python-tests]][workflow-python-tests]
55

6-
This repository provides a playground to safely experiment with and learn Azure API Management (APIM) policies in various architectures.
6+
This repository provides a playground to safely experiment with and learn Azure API Management (APIM) policies in various architectures.
77

88
_If you are interested in APIM & Azure OpenAI integrations, please check out the excellent [AI Gateway][ai-gateway] GitHub repository._
99

@@ -19,11 +19,13 @@ _Try it out, learn from it, apply it in your setups._
1919

2020
## 📁 List of Infrastructures
2121

22-
| Infrastructure Name | Description |
23-
|:----------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
24-
| [Simple API Management][infra-simple-apim] | Just the basics with a publicly accessible API Management instance fronting your APIs. This is the innermost way to experience and experiment with the APIM policies. |
25-
| [API Management & Container Apps][infra-apim-aca] | APIs are often implemented in containers running in Azure Container Apps. This architecture accesses the container apps publicly. It's beneficial to test both APIM and container app URLs to contrast and compare experiences of API calls through and bypassing APIM. It is not intended to be a security baseline. |
26-
| [Secure Front Door & API Management & Container Apps][infra-afd-apim-pe] | A higher-fidelity implementation of a secured setup in which Azure Front Door connects to APIM via the new private link integration. This traffic, once it traverses through Front Door, rides entirely on Microsoft-owned and operated networks. Similarly, the connection from APIM to Container Apps is secured but through a VNet configuration (it is also entirely possible to do this via private link). APIM Standard V2 is used here to accept a private link from Front Door. |
22+
| Infrastructure Name | Description |
23+
|:-------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
24+
| [Simple API Management][infra-simple-apim] | Just the basics with a publicly accessible API Management instance fronting your APIs. This is the innermost way to experience and experiment with the APIM policies. |
25+
| [API Management & Container Apps][infra-apim-aca] | APIs are often implemented in containers running in Azure Container Apps. This architecture accesses the container apps publicly. It's beneficial to test both APIM and container app URLs to contrast and compare experiences of API calls through and bypassing APIM. It is not intended to be a security baseline. |
26+
| [Front Door & API Management & Container Apps][infra-afd-apim-pe] | A secure implementation of Azure Front Door connecting to APIM via the new private link integration. This traffic, once it traverses through Front Door, rides entirely on Microsoft-owned and operated networks. The connection from APIM to Container Apps is secured but through a VNet configuration (it is also entirely possible to do this via private link). APIM Standard V2 is used here to accept a private link from Front Door. |
27+
| [Application Gateway (Private Endpoint) & API Management & Container Apps][infra-appgw-apim-pe] | A secure implementation of Azure Application Gateway connecting to APIM via the new private link integration. This traffic, once it traverses through App Gateway, uses a private endpoint set up in the VNet's private endpoint subnet. The connection from APIM to Container Apps is secured but through a VNet configuration (it is also entirely possible to do this via private link). APIM Standard V2 is used here to accept a private link from App Gateway. |
28+
| Application Gateway (VNet) & API Management & Container Apps | *ETA TBD - Stay tuned!* |
2729

2830
## 📁 List of Samples
2931

@@ -49,8 +51,8 @@ The fastest way to get started is using our pre-configured development environme
4951

5052
- **GitHub Codespaces**: Click the green "Code" button → "Codespaces" → "Create codespace on main"
5153
- **VS Code Dev Containers**: Install the [Dev Containers extension][vscode-devcontainers], then "Reopen in Container"
52-
53-
All prerequisites are automatically installed and configured.
54+
*
55+
All prerequisites are automatically installed and configured.
5456

5557
📖 **For detailed setup information, troubleshooting, and optimization details, see [Dev Container Documentation](.devcontainer/README.md)**
5658

@@ -61,7 +63,7 @@ All prerequisites are automatically installed and configured.
6163
These prerequisites apply broadly across all infrastructure and samples. If there are specific deviations, expect them to be noted there.
6264

6365
- [Python 3.12][python] installed
64-
- Python 3.13 may not have all dependencies ready yet. There have been issues during installs.
66+
- Python 3.13 and 3.14 should work as well, but have not been verified extensively
6567
- [VS Code][vscode] installed with the [Jupyter notebook extension][vscode-jupyter] enabled
6668
- [Azure CLI][azure-cli-install] installed
6769
- [An Azure Subscription][azure-free] with Owner or Contributor+UserAccessAdministrator permissions. Execute [Verify Azure Account][verify-az-account-notebook] to verify.
@@ -109,7 +111,7 @@ If you're setting up locally without the dev container:
109111

110112
That's it! Your local environment now matches the dev container experience with:
111113
- ✅ Standardized "APIM Samples Python 3.12" Jupyter kernel
112-
- ✅ Automatic notebook kernel selection
114+
- ✅ Automatic notebook kernel selection
113115
- ✅ Python path configured for shared modules
114116
- ✅ VS Code optimized for the project
115117

@@ -131,7 +133,7 @@ If you prefer manual setup or the automated script doesn't work:
131133
1. Set up the project environment:
132134
```bash
133135
python setup/setup_python_path.py --generate-env
134-
python setup/setup_python_path.py --setup-kernel
136+
python setup/setup_python_path.py --setup-kernel
135137
python setup/setup_python_path.py --setup-vscode
136138
```
137139
1. **Restart VS Code** to ensure all environment settings are loaded properly.
@@ -177,7 +179,7 @@ Now that infrastructure and sample have been stood up, you can experiment with t
177179
Encountering issues? Check our comprehensive **[Troubleshooting Guide](TROUBLESHOOTING.md)** which covers:
178180

179181
- **Deployment Errors** - Including the common "content already consumed" error and parameter mismatches
180-
- **Authentication Issues** - Azure CLI login problems and permission errors
182+
- **Authentication Issues** - Azure CLI login problems and permission errors
181183
- **Notebook & Development Environment Issues** - Module import errors and Python path problems
182184
- **Azure CLI Issues** - Rate limiting and API version compatibility
183185
- **Resource Management Issues** - Resource group and APIM service problems
@@ -192,10 +194,10 @@ For immediate help with common errors, diagnostic commands, and step-by-step sol
192194

193195
- All _samples_ can be found in the `samples` folder. Samples showcase functionality and provide a baseline for your experimentation.
194196
- All _infrastructures_ can be found in the `infrastructure` folder. They provide the architectural underpinnings.
195-
- All shared code, modules, functionality, policies, etc. can be found in the `shared` folder.
197+
- All shared code, modules, functionality, policies, etc. can be found in the `shared` folder.
196198
- Bicep _modules_ are versioned in the `bicep/modules` folder. Major changes require versioning.
197-
- Python _modules_ are found in the `python` folder. _They are not versioned yet but may be in the future._
198-
- Reusable _APIM policies_ are found in the `apim-policies` folder.
199+
- Python _modules_ are found in the `python` folder. _They are not versioned yet but may be in the future._
200+
- Reusable _APIM policies_ are found in the `apim-policies` folder.
199201
- Reusable Jupyter notebooks are found in the `jupyter` folder.
200202

201203
### ⚙️ Sample Setup
@@ -245,7 +247,7 @@ All pylint runs generate timestamped reports in `tests/python/pylint/reports/`:
245247
- **Text format**: Human-readable detailed analysis
246248
- **Latest symlinks**: `latest.json` and `latest.txt` always point to the most recent run
247249

248-
The script automatically displays a **Top 10 Issues Summary** showing the most frequent code quality issues to help prioritize improvements.
250+
The script automatically displays a **Top 10 Issues Summary** showing the most frequent code quality issues to help prioritize improvements.
249251

250252
### ➕ Adding a Sample
251253

assets/diagrams/out/appgw-pe-apim-aca-architecture/Azure Application Gateway, API Management & Container Apps Architecture.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
@startuml "Azure Application Gateway, API Management & Container Apps Architecture"
2+
3+
!include ./base.puml
4+
5+
title Azure Application Gateway, API Management & Container Apps Architecture
6+
7+
' Main components
8+
AzureApplicationGateway(appgw, "Application Gateway (WAF)", "")
9+
AzureAPIManagement(apim, "API Management", "")
10+
AzureContainerApp(aca, "Container Apps", "")
11+
AzureApplicationInsights(appinsights, "Application Insights", "")
12+
AzureLogAnalyticsWorkspace(loganalytics, "Log Analytics", "")
13+
14+
' Custom components
15+
collections "Apps" as apps #LightBlue
16+
17+
' Relationships
18+
apps --> appgw : "API Consumers"
19+
appgw --> apim : "Routes traffic (via Private Endpoint)"
20+
apim --> aca : "Backend"
21+
apim -right-> appinsights : "\nSends\ntelemetry\n"
22+
appinsights -down-> loganalytics : "Stores data"
23+
24+
@enduml

assets/diagrams/src/base.puml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
!includeurl AzurePuml/Analytics/AzureLogAnalyticsWorkspace.puml
1010
!includeurl AzurePuml/Containers/AzureContainerApp.puml
1111
!includeurl AzurePuml/Networking/AzureFrontDoor.puml
12+
!includeurl AzurePuml/Networking/AzureApplicationGateway.puml
1213

1314
skinparam titleFontSize 24
14-
left to right direction
15+
left to right direction

infrastructure/afd-apim-pe/create_infrastructure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def create_infrastructure(location: str, index: int, apim_sku: APIM_SKU, no_aca:
2626
print(f'\n💥 Error: {str(e)}')
2727
sys.exit(1)
2828

29-
3029
def _create_afd_specific_apis(use_aca: bool = True) -> list[API]:
3130
"""
3231
Create AFD-APIM-PE specific APIs with optional Container Apps backends.
@@ -60,6 +59,7 @@ def _create_afd_specific_apis(use_aca: bool = True) -> list[API]:
6059
return [api_hwaca_1, api_hwaca_2, api_hwaca_pool]
6160

6261
return []
62+
6363
def main():
6464
"""
6565
Main entry point for command-line usage.

infrastructure/appgw-apim-pe/Azure Application Gateway, API Management & Container Apps Architecture.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Application Gateway & API Management & Container Apps Infrastructure
2+
3+
Secure architecture that takes all traffic off the public Internet once Azure Application (App) Gateway is traversed. Traffic behind the App Gateway is subsequently inaccessible to the public. This is due to App Gateways's use of a private link to Azure API Management.
4+
5+
<img src="./Azure Application Gateway, API Management & Container Apps Architecture.svg" alt="Diagram showing Azure Application Gateway, API Management, and Container Apps architecture. Azure Application Gateway routes traffic to API Management, which then routes to Container Apps. Telemetry is sent to Azure Monitor." title="Azure Application Gateway, API Management & Container Apps Architecture" width="1000" />
6+
7+
## 🎯 Objectives
8+
9+
1. Provide a secure pathway to API Management via a private link from App Gateway
10+
1. Maintain private networking by integrating API Management with a VNet to communicate with Azure Container Apps. (This can also be achieved via a private link there)
11+
1. Empower users to use Azure Container Apps, if desired
12+
1. Enable observability by sending telemetry to Azure Monitor
13+
14+
## ⚙️ Configuration
15+
16+
Adjust the `user-defined parameters` in this lab's Jupyter Notebook's [Initialize notebook variables][init-notebook-variables] section.
17+
18+
## ▶️ Execution
19+
20+
👟 **Expected *Run All* runtime: ~13 minutes**
21+
22+
1. Execute this lab's [Jupyter Notebook][infra-notebook] step-by-step or via _Run All_.
23+
24+
## 🧪 Testing
25+
26+
Unlike Azure Front Door, App Gateway does not presently support managed certificates. This complicates the infrastructure as it either requires the user to bring their own certificate, or a self-signed certificate needs to be generated and made available to App Gateway.
27+
28+
We opted for the latter as it is more conducive to generate a self-signed certificate and work with its appropriate and secure limitations. This does mean that, for the purpose of this being non-production, proof of concept infrastructure, we need to trust the self-signed cert appropriately. We do so by acknowledging and subsequently ignoring the self-signed certificate warnings and using IPs paired with `Host` header.
29+
30+
**Production workloads must not use this approach and, instead, be secured appropriately.**
31+
32+
33+
34+
[init-notebook-variables]: ./create.ipynb#initialize-notebook-variables
35+
[infra-notebook]: ./create.ipynb
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"### 🗑️ Clean up resources\n",
8+
"\n",
9+
"When you're finished with the lab, you should remove all your deployed resources from Azure to avoid extra charges and keep your Azure subscription uncluttered."
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": null,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"import utils\n",
19+
"from apimtypes import INFRASTRUCTURE\n",
20+
"\n",
21+
"deployment = INFRASTRUCTURE.APPGW_APIM_PE\n",
22+
"indexes = [1]\n",
23+
"\n",
24+
"utils.cleanup_infra_deployments(deployment, indexes)"
25+
]
26+
}
27+
],
28+
"metadata": {
29+
"kernelspec": {
30+
"display_name": ".venv (3.12.10)",
31+
"language": "python",
32+
"name": "python3"
33+
},
34+
"language_info": {
35+
"codemirror_mode": {
36+
"name": "ipython",
37+
"version": 3
38+
},
39+
"file_extension": ".py",
40+
"mimetype": "text/x-python",
41+
"name": "python",
42+
"nbconvert_exporter": "python",
43+
"pygments_lexer": "ipython3",
44+
"version": "3.12.10"
45+
}
46+
},
47+
"nbformat": 4,
48+
"nbformat_minor": 2
49+
}

0 commit comments

Comments
 (0)