Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
126 changes: 20 additions & 106 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,114 +1,28 @@
{
// Whitespace and formatting
"jupyter.defaultKernel": "apim-samples",
"jupyter.kernels.changeKernelIdForNotebookEnabled": false,
"jupyter.preferredKernelIdForNotebook": {
"*.ipynb": "apim-samples"
},
"jupyter.kernels.trusted": [
"./.venv/Scripts/python.exe"
],
"jupyter.kernels.excludePythonEnvironments": [
"apim-samples"
],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"editor.renderWhitespace": "trailing",

// PlantUML
"plantuml.diagramsRoot": "assets/diagrams/src",
"python.defaultInterpreterPath": "./.venv/Scripts/python.exe",
"python.pythonPath": "./.venv/Scripts/python.exe",
"python.envFile": "${workspaceFolder}/.env",
"notebook.defaultLanguage": "python",
"notebook.kernelPickerType": "mru",
"terminal.integrated.defaultProfile.windows": "PowerShell",
"plantuml.render": "Local",
"plantuml.exportFormat": "svg",
"plantuml.exportOutDir": "assets/diagrams/out",
"plantuml.java": "C:\\Program Files\\OpenJDK\\jdk-22.0.2\\bin\\java.exe",
"plantuml.render": "Local",
"python.analysis.autoIndent": true,
"python.analysis.completeFunctionParens": true,
"python.analysis.diagnosticSeverityOverrides": {
"reportDuplicateImport": "warning",
"reportUndefinedVariable": "information",
"reportUnusedVariable": "information"
},
"python.analysis.extraPaths": [
"${workspaceFolder}/shared/python"
],
"python.defaultInterpreterPath": "/workspaces/Apim-Samples/.venv/bin/python",
"python.pythonPath": "/workspaces/Apim-Samples/.venv/bin/python",
"python.envFile": "${workspaceFolder}/.env",
"python.terminal.activateEnvironment": true,
"python.terminal.activateEnvInCurrentTerminal": true,
"jupyter.askForKernelRestart": false,
"jupyter.interactiveWindow.textEditor.executeSelection": true,
"jupyter.notebookFileRoot": "${workspaceFolder}",
"jupyter.kernels.excludePythonEnvironments": [
"**/anaconda3/**",
"**/conda/**",
"**/miniconda3/**",
"**/python3.*",
"*/site-packages/*",
"/bin/python",
"/bin/python3",
"/opt/python/*/bin/python*",
"/usr/bin/python",
"/usr/bin/python3",
"/usr/local/bin/python",
"/usr/local/bin/python3",
"python",
"python3"
],
"jupyter.kernels.trusted": [
"/workspaces/Apim-Samples/.venv/bin/python"
],
"terminal.integrated.env.windows": {
"PATH": "${env:PATH}"
},
"terminal.integrated.showExitAlert": false,
"terminal.integrated.focusAfterRun": "terminal",
"terminal.integrated.defaultProfile.linux": "bash",
"workbench.panel.defaultLocation": "bottom",
"workbench.startupEditor": "none",
"workbench.panel.defaultPanelHeight": 350,
"workbench.view.alwaysShowHeaderActions": true,
"terminal.integrated.tabs.enabled": true,
"terminal.integrated.tabs.location": "left",
"xml.validation.enabled": false,
"xml.validation.namespaces.enabled": "never",
"xml.validation.schema.enabled": "never",
"xml.validation.disallowDocTypeDecl": false,
"xml.validation.resolveExternalEntities": false,
"xml.format.enabled": false,
"xml.format.emptyElements": "ignore",
"xml.format.enforceQuoteStyle": "preferred",
"xml.format.preserveEmptyContent": true,
"xml.format.preserveSpace": [
"xsl:text",
"xsl:comment",
"xsl:processing-instruction",
"literal",
"xsl:preserve-space",
"fragment",
"condition"
],
"xml.format.splitAttributes": "preserve",
"xml.format.joinCDATALines": false,
"xml.format.joinCommentLines": false,
"xml.format.joinContentLines": false,
"xml.format.spaceBeforeEmptyCloseTag": true,
"xml.format.xsiSchemaLocationSplit": "onPair",
"xml.completion.autoCloseTags": true,
"xml.codeLens.enabled": false,
"xml.preferences.includeSchemaAssociations": "never",
"xml.trace.server": "off",
"files.associations": {
"*.xml": "xml",
"**/apim-policies/*.xml": "xml",
"**/samples/**/*.xml": "xml",
"pf-*.xml": "xml",
"hr_*.xml": "xml"
},
"html.validate": false,
"azureApiManagement.policies.validateSyntax": true,
"azureApiManagement.policies.showCodeLens": true,
"[xml]": {
"editor.quickSuggestions": {
"other": true,
"comments": false,
"strings": true
},
"editor.autoClosingBrackets": "always",
"editor.autoClosingQuotes": "always",
"editor.suggest.insertMode": "replace",
"editor.formatOnSave": false,
"editor.formatOnPaste": false,
"editor.formatOnType": false
}
"plantuml.diagramsRoot": "assets/diagrams/src",
"plantuml.exportOutDir": "assets/diagrams/out"
}
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/11057/badge)](https://www.bestpractices.dev/projects/11057)
[![Python Tests][badge-python-tests]][workflow-python-tests]

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

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

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

## 📁 List of Infrastructures

| Infrastructure Name | Description |
|:----------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [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. |
| [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. |
| [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. |
| Infrastructure Name | Description |
|:-------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [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. |
| [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. |
| [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. |
| [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. |
| Application Gateway (VNet) & API Management & Container Apps | *ETA TBD - Stay tuned!* |

## 📁 List of Samples

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

- **GitHub Codespaces**: Click the green "Code" button → "Codespaces" → "Create codespace on main"
- **VS Code Dev Containers**: Install the [Dev Containers extension][vscode-devcontainers], then "Reopen in Container"

All prerequisites are automatically installed and configured.
*
All prerequisites are automatically installed and configured.

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

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

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

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

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

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

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

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

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

### ➕ Adding a Sample

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions assets/diagrams/src/appgw-pe-apim-aca-architecture.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@startuml "Azure Application Gateway, API Management & Container Apps Architecture"

!include ./base.puml

title Azure Application Gateway, API Management & Container Apps Architecture

' Main components
AzureApplicationGateway(appgw, "Application Gateway (WAF)", "")
AzureAPIManagement(apim, "API Management", "")
AzureContainerApp(aca, "Container Apps", "")
AzureApplicationInsights(appinsights, "Application Insights", "")
AzureLogAnalyticsWorkspace(loganalytics, "Log Analytics", "")

' Custom components
collections "Apps" as apps #LightBlue

' Relationships
apps --> appgw : "API Consumers"
appgw --> apim : "Routes traffic (via Private Endpoint)"
apim --> aca : "Backend"
apim -right-> appinsights : "\nSends\ntelemetry\n"
appinsights -down-> loganalytics : "Stores data"

@enduml
3 changes: 2 additions & 1 deletion assets/diagrams/src/base.puml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
!includeurl AzurePuml/Analytics/AzureLogAnalyticsWorkspace.puml
!includeurl AzurePuml/Containers/AzureContainerApp.puml
!includeurl AzurePuml/Networking/AzureFrontDoor.puml
!includeurl AzurePuml/Networking/AzureApplicationGateway.puml

skinparam titleFontSize 24
left to right direction
left to right direction
2 changes: 1 addition & 1 deletion infrastructure/afd-apim-pe/create_infrastructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ def create_infrastructure(location: str, index: int, apim_sku: APIM_SKU, no_aca:
print(f'\n💥 Error: {str(e)}')
sys.exit(1)


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

return []

def main():
"""
Main entry point for command-line usage.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions infrastructure/appgw-apim-pe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Application Gateway & API Management & Container Apps Infrastructure

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.

<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" />

## 🎯 Objectives

1. Provide a secure pathway to API Management via a private link from App Gateway
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)
1. Empower users to use Azure Container Apps, if desired
1. Enable observability by sending telemetry to Azure Monitor

## ⚙️ Configuration

Adjust the `user-defined parameters` in this lab's Jupyter Notebook's [Initialize notebook variables][init-notebook-variables] section.

## ▶️ Execution

👟 **Expected *Run All* runtime: ~13 minutes**

1. Execute this lab's [Jupyter Notebook][infra-notebook] step-by-step or via _Run All_.

## 🧪 Testing

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.

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.

**Production workloads must not use this approach and, instead, be secured appropriately.**



[init-notebook-variables]: ./create.ipynb#initialize-notebook-variables
[infra-notebook]: ./create.ipynb
49 changes: 49 additions & 0 deletions infrastructure/appgw-apim-pe/clean-up.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 🗑️ Clean up resources\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import utils\n",
"from apimtypes import INFRASTRUCTURE\n",
"\n",
"deployment = INFRASTRUCTURE.APPGW_APIM_PE\n",
"indexes = [1]\n",
"\n",
"utils.cleanup_infra_deployments(deployment, indexes)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv (3.12.10)",
"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.10"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading
Loading