From 06f9c416c8dbeeb22ca29007e5a27077ba7a7c3d Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Mon, 12 Jun 2023 21:14:23 +0200 Subject: [PATCH 01/27] Update documentation --- README.md | 43 ++++++++++++++++++++++++++++++++++++++ code/infra/vars.dev.tfvars | 1 + 2 files changed, 44 insertions(+) diff --git a/README.md b/README.md index f9f0fe7..2829d0f 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,46 @@ This repository provides a scalable baseline for Azure Functions written in Pyth 1. A compliant infrastructure baseline written in Terraform, 2. A Python code baseline that follows best practices and 3. A safe rollout mechanism of code artifacts. + +## Infrastructure + +The infrastructure as code (IaC) is written in Terraform and uses all the latest and greatest Azure Function features to ensure high security standards and the lowest attack surface possible. The code can be found in the [`/code/infra` folder](/code/infra/) and creates the following resources: + +* App Service Plan, +* Azure Function, +* Azure Storage Account, +* Azure Key Vault, +* Azure Application Insights and +* Azure Log Analytics Workspace. + +The Azure Function is configured in a way to fulfill highest compliance standards. In addition, the end-to-end setup takes care of wiring up all services to ensure a productive experience on day one. For instance, the Azure Function is automatically being connected to Azure Application Insights and the Application Insights service is being connected to the Azure Log Analytics Workspace. + +### Network configuration + +The deployed services ensure a compliant network setup using the following features: + +* Public network access is denied for all services. +* All deployed services rely on Azure Private Endpoints for all network flows including deployments and usage of the services. + +### Authentication & Authorization + +The deployed services ensure a compliant authentication & authorization setup using the following features: + +* No key-based or local/basic authentication flows. +* Azure AD-only authentication. +* All authorization is controlled by Azure RBAC. +* This includes the interaction of the Azure Function with the Azure Storage Account and the Azure Key Vault. + +### Encryption + +The deployed services ensure a compliant encryption setup using the following features: + +* Encryption at rest using 256-bit AES (FIPS 140-2). +* HTTPS traffic only. +* All traffic is encrypted using TLS 1.2. +* Note: Customer-manaed keys are not used at this point in time but can be added easily. +* Note: Cypher suites are set to default and can further be limited. + +## Azure Function Code + +TODO diff --git a/code/infra/vars.dev.tfvars b/code/infra/vars.dev.tfvars index 7af9c13..44970b3 100644 --- a/code/infra/vars.dev.tfvars +++ b/code/infra/vars.dev.tfvars @@ -2,6 +2,7 @@ location = "northeurope" environment = "dev" prefix = "myfunc" tags = {} +python_version = "3.10" vnet_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/virtualNetworks/mycrp-prd-function-vnet001" nsg_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/networkSecurityGroups/mycrp-prd-function-nsg001" route_table_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/routeTables/mycrp-prd-function-rt001" From 278aa5e3103560fb4d2cd26fd7c5a6a189121780 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 10:19:03 +0200 Subject: [PATCH 02/27] Update function configuration --- .github/workflows/functionApp.yml | 2 +- code/function/host.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/functionApp.yml b/.github/workflows/functionApp.yml index ab7c056..072d549 100644 --- a/.github/workflows/functionApp.yml +++ b/.github/workflows/functionApp.yml @@ -24,7 +24,7 @@ jobs: uses: ./.github/workflows/_functionAppDeployTemplate.yml name: "Function App Deploy" needs: [function_test] - if: github.event_name == 'push' || github.event_name == 'release' + # if: github.event_name == 'push' || github.event_name == 'release' with: environment: "dev" python_version: "3.10" diff --git a/code/function/host.json b/code/function/host.json index 06d01bd..1c14b6a 100644 --- a/code/function/host.json +++ b/code/function/host.json @@ -11,5 +11,10 @@ "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" + }, + "extensions": { + "http": { + "routePrefix": "" + } } } From 60249144b072ad20e28614931c1a6a240af59ed7 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 10:30:57 +0200 Subject: [PATCH 03/27] Update triggers --- .github/workflows/functionApp.yml | 2 ++ .github/workflows/terraform.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/functionApp.yml b/.github/workflows/functionApp.yml index 072d549..db7f0ca 100644 --- a/.github/workflows/functionApp.yml +++ b/.github/workflows/functionApp.yml @@ -5,12 +5,14 @@ on: - main paths: - "**.py" + - "code/function/**" pull_request: branches: - main paths: - "**.py" + - "code/function/**" jobs: function_test: diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml index f1a9d92..e1618dc 100644 --- a/.github/workflows/terraform.yml +++ b/.github/workflows/terraform.yml @@ -5,12 +5,14 @@ on: - main paths: - "**.tf" + - "code/infra/**" pull_request: branches: - main paths: - "**.tf" + - "code/infra/**" jobs: terraform_lint: From 8ebc703a48f06559bef4576a5d625306288aba81 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 10:56:55 +0200 Subject: [PATCH 04/27] Update entrypoint --- code/function/function_app.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/function/function_app.py b/code/function/function_app.py index fe89a11..1f9c587 100644 --- a/code/function/function_app.py +++ b/code/function/function_app.py @@ -32,3 +32,7 @@ async def shutdown_event(): app=fastapi_app, http_auth_level=func.AuthLevel.ANONYMOUS, ) + + +async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: + return await app.handle_async(req, context) From 1aa35acb7dc01076feaa48a2efa6f6e16817db22 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 11:50:10 +0200 Subject: [PATCH 05/27] Update entry point --- code/function/function_app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/function/function_app.py b/code/function/function_app.py index 1f9c587..1da4431 100644 --- a/code/function/function_app.py +++ b/code/function/function_app.py @@ -34,5 +34,5 @@ async def shutdown_event(): ) -async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: - return await app.handle_async(req, context) +# async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: +# return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) From fed3c9d70d56dc3b51cdedb6eb4935d2476d087f Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 12:37:36 +0200 Subject: [PATCH 06/27] Add function json --- code/function/function.json | 21 +++++++++++++++++++++ code/function/function_app.py | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 code/function/function.json diff --git a/code/function/function.json b/code/function/function.json new file mode 100644 index 0000000..dde77ae --- /dev/null +++ b/code/function/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "function_app.py", + "bindings": [ + { + "authLevel": "anonymous", + "type": "httpTrigger", + "direction": "in", + "name": "req", + "methods": [ + "get", + "post" + ], + "route": "{*route}" + }, + { + "type": "http", + "direction": "out", + "name": "$return" + } + ] +} diff --git a/code/function/function_app.py b/code/function/function_app.py index 1da4431..daace99 100644 --- a/code/function/function_app.py +++ b/code/function/function_app.py @@ -34,5 +34,5 @@ async def shutdown_event(): ) -# async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: -# return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) +async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: + return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) From 1cba28c8e705c5860e46514e04c94f0b7d4fd190 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 13:26:14 +0200 Subject: [PATCH 07/27] Update function configuration --- code/function/{function_app.py => main.py} | 14 +++++++------- code/function/wrapper/__init__.py | 6 ++++++ code/function/{ => wrapper}/function.json | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) rename code/function/{function_app.py => main.py} (65%) create mode 100644 code/function/wrapper/__init__.py rename code/function/{ => wrapper}/function.json (89%) diff --git a/code/function/function_app.py b/code/function/main.py similarity index 65% rename from code/function/function_app.py rename to code/function/main.py index daace99..a91d7fd 100644 --- a/code/function/function_app.py +++ b/code/function/main.py @@ -1,4 +1,4 @@ -import azure.functions as func +# import azure.functions as func from fastapi import FastAPI from function.api.v1.api_v1 import api_v1_router from function.core.config import settings @@ -28,11 +28,11 @@ async def shutdown_event(): pass -app = func.AsgiFunctionApp( - app=fastapi_app, - http_auth_level=func.AuthLevel.ANONYMOUS, -) +# app = func.AsgiFunctionApp( +# app=fastapi_app, +# http_auth_level=func.AuthLevel.ANONYMOUS, +# ) -async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: - return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) +# async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: +# return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) diff --git a/code/function/wrapper/__init__.py b/code/function/wrapper/__init__.py new file mode 100644 index 0000000..374dcb1 --- /dev/null +++ b/code/function/wrapper/__init__.py @@ -0,0 +1,6 @@ +import azure.functions as func +from function.main import fastapi_app + + +async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: + return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) diff --git a/code/function/function.json b/code/function/wrapper/function.json similarity index 89% rename from code/function/function.json rename to code/function/wrapper/function.json index dde77ae..60ae420 100644 --- a/code/function/function.json +++ b/code/function/wrapper/function.json @@ -1,5 +1,5 @@ { - "scriptFile": "function_app.py", + "scriptFile": "__init__.py", "bindings": [ { "authLevel": "anonymous", From a568ae98bc2ee5b62e83f11b4ee1deeccf86a646 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 13:29:06 +0200 Subject: [PATCH 08/27] Update test --- tests/test_main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index f1b1ffb..b396f9d 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,7 +1,6 @@ import pytest from fastapi.testclient import TestClient -from function.core.config import settings -from function.function_app import fastapi_app +from function.main import fastapi_app @pytest.fixture(scope="module") From 45166315e2658539b0b2625c01dd01c010024ae6 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 13:46:54 +0200 Subject: [PATCH 09/27] Update main to function_app --- code/function/{main.py => function_app.py} | 0 code/function/wrapper/__init__.py | 2 +- tests/test_main.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename code/function/{main.py => function_app.py} (100%) diff --git a/code/function/main.py b/code/function/function_app.py similarity index 100% rename from code/function/main.py rename to code/function/function_app.py diff --git a/code/function/wrapper/__init__.py b/code/function/wrapper/__init__.py index 374dcb1..db918fc 100644 --- a/code/function/wrapper/__init__.py +++ b/code/function/wrapper/__init__.py @@ -1,5 +1,5 @@ import azure.functions as func -from function.main import fastapi_app +from function.function_app import fastapi_app async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: diff --git a/tests/test_main.py b/tests/test_main.py index b396f9d..f527886 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,6 @@ import pytest from fastapi.testclient import TestClient -from function.main import fastapi_app +from function.function_app import fastapi_app @pytest.fixture(scope="module") From b021b25ee6738a083925fc00fcd7d176977b07e1 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 14:24:25 +0200 Subject: [PATCH 10/27] Update config --- code/function/__init__.py | 0 code/function/{function_app.py => main.py} | 0 code/function/wrapper/__init__.py | 2 +- tests/test_main.py | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 code/function/__init__.py rename code/function/{function_app.py => main.py} (100%) diff --git a/code/function/__init__.py b/code/function/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/function/function_app.py b/code/function/main.py similarity index 100% rename from code/function/function_app.py rename to code/function/main.py diff --git a/code/function/wrapper/__init__.py b/code/function/wrapper/__init__.py index db918fc..374dcb1 100644 --- a/code/function/wrapper/__init__.py +++ b/code/function/wrapper/__init__.py @@ -1,5 +1,5 @@ import azure.functions as func -from function.function_app import fastapi_app +from function.main import fastapi_app async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: diff --git a/tests/test_main.py b/tests/test_main.py index f527886..b396f9d 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,6 @@ import pytest from fastapi.testclient import TestClient -from function.function_app import fastapi_app +from function.main import fastapi_app @pytest.fixture(scope="module") From 8b204658e51e0f0413ad81dcbcd3a2c0cfd396f4 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 15:53:20 +0200 Subject: [PATCH 11/27] Update function folder structure --- README.md | 2 +- code/function/{ => fastapi}/__init__.py | 0 code/function/{ => fastapi}/api/__init__.py | 0 .../function/{ => fastapi}/api/v1/__init__.py | 0 code/function/{ => fastapi}/api/v1/api_v1.py | 2 +- .../api/v1/endpoints/heartbeat.py | 4 +- .../{ => fastapi}/api/v1/endpoints/sample.py | 4 +- code/function/{ => fastapi}/core/__init__.py | 0 code/function/{ => fastapi}/core/config.py | 0 code/function/{ => fastapi}/core/messages.py | 0 code/function/fastapi/main.py | 27 +++++++++++++ .../function/{ => fastapi}/models/__init__.py | 0 .../{ => fastapi}/models/heartbeat.py | 0 code/function/{ => fastapi}/models/sample.py | 0 code/function/{ => fastapi}/utils.py | 2 +- code/function/main.py | 38 ------------------- code/function/wrapper/__init__.py | 4 +- code/infra/function.tf | 4 ++ tests/test_main.py | 2 +- 19 files changed, 41 insertions(+), 48 deletions(-) rename code/function/{ => fastapi}/__init__.py (100%) rename code/function/{ => fastapi}/api/__init__.py (100%) rename code/function/{ => fastapi}/api/v1/__init__.py (100%) rename code/function/{ => fastapi}/api/v1/api_v1.py (79%) rename code/function/{ => fastapi}/api/v1/endpoints/heartbeat.py (76%) rename code/function/{ => fastapi}/api/v1/endpoints/sample.py (76%) rename code/function/{ => fastapi}/core/__init__.py (100%) rename code/function/{ => fastapi}/core/config.py (100%) rename code/function/{ => fastapi}/core/messages.py (100%) create mode 100644 code/function/fastapi/main.py rename code/function/{ => fastapi}/models/__init__.py (100%) rename code/function/{ => fastapi}/models/heartbeat.py (100%) rename code/function/{ => fastapi}/models/sample.py (100%) rename code/function/{ => fastapi}/utils.py (93%) delete mode 100644 code/function/main.py diff --git a/README.md b/README.md index 2829d0f..44cc49e 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,4 @@ The deployed services ensure a compliant encryption setup using the following fe ## Azure Function Code -TODO +The Azure Function code is written in Python and leverages the new [Web Framework integration](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=asgi%2Capplication-level&pivots=python-mode-decorators#web-frameworks) supported by the v2 Python programming model. diff --git a/code/function/__init__.py b/code/function/fastapi/__init__.py similarity index 100% rename from code/function/__init__.py rename to code/function/fastapi/__init__.py diff --git a/code/function/api/__init__.py b/code/function/fastapi/api/__init__.py similarity index 100% rename from code/function/api/__init__.py rename to code/function/fastapi/api/__init__.py diff --git a/code/function/api/v1/__init__.py b/code/function/fastapi/api/v1/__init__.py similarity index 100% rename from code/function/api/v1/__init__.py rename to code/function/fastapi/api/v1/__init__.py diff --git a/code/function/api/v1/api_v1.py b/code/function/fastapi/api/v1/api_v1.py similarity index 79% rename from code/function/api/v1/api_v1.py rename to code/function/fastapi/api/v1/api_v1.py index 4c9c462..488ff98 100644 --- a/code/function/api/v1/api_v1.py +++ b/code/function/fastapi/api/v1/api_v1.py @@ -1,5 +1,5 @@ from fastapi import APIRouter -from function.api.v1.endpoints import heartbeat, sample +from fastapi.api.v1.endpoints import heartbeat, sample api_v1_router = APIRouter() api_v1_router.include_router(sample.router, prefix="/sample", tags=["sample"]) diff --git a/code/function/api/v1/endpoints/heartbeat.py b/code/function/fastapi/api/v1/endpoints/heartbeat.py similarity index 76% rename from code/function/api/v1/endpoints/heartbeat.py rename to code/function/fastapi/api/v1/endpoints/heartbeat.py index dd03420..c3015be 100644 --- a/code/function/api/v1/endpoints/heartbeat.py +++ b/code/function/fastapi/api/v1/endpoints/heartbeat.py @@ -1,8 +1,8 @@ from typing import Any from fastapi import APIRouter -from function.models.heartbeat import HearbeatResult -from function.utils import setup_logging +from fastapi.models.heartbeat import HearbeatResult +from fastapi.utils import setup_logging logger = setup_logging(__name__) diff --git a/code/function/api/v1/endpoints/sample.py b/code/function/fastapi/api/v1/endpoints/sample.py similarity index 76% rename from code/function/api/v1/endpoints/sample.py rename to code/function/fastapi/api/v1/endpoints/sample.py index 5f4fc62..0442916 100644 --- a/code/function/api/v1/endpoints/sample.py +++ b/code/function/fastapi/api/v1/endpoints/sample.py @@ -1,8 +1,8 @@ from typing import Any from fastapi import APIRouter -from function.models.sample import SampleRequest, SampleResponse -from function.utils import setup_logging +from fastapi.models.sample import SampleRequest, SampleResponse +from fastapi.utils import setup_logging logger = setup_logging(__name__) diff --git a/code/function/core/__init__.py b/code/function/fastapi/core/__init__.py similarity index 100% rename from code/function/core/__init__.py rename to code/function/fastapi/core/__init__.py diff --git a/code/function/core/config.py b/code/function/fastapi/core/config.py similarity index 100% rename from code/function/core/config.py rename to code/function/fastapi/core/config.py diff --git a/code/function/core/messages.py b/code/function/fastapi/core/messages.py similarity index 100% rename from code/function/core/messages.py rename to code/function/fastapi/core/messages.py diff --git a/code/function/fastapi/main.py b/code/function/fastapi/main.py new file mode 100644 index 0000000..de13852 --- /dev/null +++ b/code/function/fastapi/main.py @@ -0,0 +1,27 @@ +from fastapi import FastAPI +from fastapi.api.v1.api_v1 import api_v1_router +from fastapi.core.config import settings + + +def get_app() -> FastAPI: + app = FastAPI( + title=settings.PROJECT_NAME, + version=settings.APP_VERSION, + openapi_url="/openapi.json", + debug=settings.DEBUG, + ) + app.include_router(api_v1_router, prefix=settings.API_V1_STR) + return app + + +app = get_app() + + +@app.on_event("startup") +async def startup_event(): + pass + + +@app.on_event("shutdown") +async def shutdown_event(): + pass diff --git a/code/function/models/__init__.py b/code/function/fastapi/models/__init__.py similarity index 100% rename from code/function/models/__init__.py rename to code/function/fastapi/models/__init__.py diff --git a/code/function/models/heartbeat.py b/code/function/fastapi/models/heartbeat.py similarity index 100% rename from code/function/models/heartbeat.py rename to code/function/fastapi/models/heartbeat.py diff --git a/code/function/models/sample.py b/code/function/fastapi/models/sample.py similarity index 100% rename from code/function/models/sample.py rename to code/function/fastapi/models/sample.py diff --git a/code/function/utils.py b/code/function/fastapi/utils.py similarity index 93% rename from code/function/utils.py rename to code/function/fastapi/utils.py index a27ac01..4934bac 100644 --- a/code/function/utils.py +++ b/code/function/fastapi/utils.py @@ -1,7 +1,7 @@ import logging from logging import Logger -from function.core.config import settings +from fastapi.core.config import settings def setup_logging(module) -> Logger: diff --git a/code/function/main.py b/code/function/main.py deleted file mode 100644 index a91d7fd..0000000 --- a/code/function/main.py +++ /dev/null @@ -1,38 +0,0 @@ -# import azure.functions as func -from fastapi import FastAPI -from function.api.v1.api_v1 import api_v1_router -from function.core.config import settings - - -def get_app() -> FastAPI: - app = FastAPI( - title=settings.PROJECT_NAME, - version=settings.APP_VERSION, - openapi_url="/openapi.json", - debug=settings.DEBUG, - ) - app.include_router(api_v1_router, prefix=settings.API_V1_STR) - return app - - -fastapi_app = get_app() - - -@fastapi_app.on_event("startup") -async def startup_event(): - pass - - -@fastapi_app.on_event("shutdown") -async def shutdown_event(): - pass - - -# app = func.AsgiFunctionApp( -# app=fastapi_app, -# http_auth_level=func.AuthLevel.ANONYMOUS, -# ) - - -# async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: -# return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) diff --git a/code/function/wrapper/__init__.py b/code/function/wrapper/__init__.py index 374dcb1..a52a5a9 100644 --- a/code/function/wrapper/__init__.py +++ b/code/function/wrapper/__init__.py @@ -1,6 +1,6 @@ import azure.functions as func -from function.main import fastapi_app +from fastapi.main import app async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: - return await func.AsgiMiddleware(fastapi_app).handle_async(req, context) + return await func.AsgiMiddleware(app).handle_async(req, context) diff --git a/code/infra/function.tf b/code/infra/function.tf index 68dc919..f62e75e 100644 --- a/code/infra/function.tf +++ b/code/infra/function.tf @@ -72,6 +72,10 @@ resource "azapi_resource" "function" { name = "WEBSITE_RUN_FROM_PACKAGE" value = "1" }, + { + name = "PYTHON_ENABLE_WORKER_EXTENSIONS" + value = "1" + }, { name = "AzureWebJobsStorage__accountName" value = azurerm_storage_account.storage.name diff --git a/tests/test_main.py b/tests/test_main.py index b396f9d..1fa8ff4 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,6 @@ import pytest from fastapi.testclient import TestClient -from function.main import fastapi_app +from fastapi.main import fastapi_app @pytest.fixture(scope="module") From 2c959206dcdca8eeb12bf1ca3fed5dcf0b7c1462 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 15:54:31 +0200 Subject: [PATCH 12/27] Update test config --- pytest.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest.ini b/pytest.ini index 1d9b4af..1ff3a7c 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,2 @@ [pytest] -pythonpath = code +pythonpath = code/function From 302d47402b005ac7a1fbf0a318a21df9c105970f Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 15:58:33 +0200 Subject: [PATCH 13/27] Update folder name --- code/function/{fastapi => fastapp}/__init__.py | 0 code/function/{fastapi => fastapp}/api/__init__.py | 0 code/function/{fastapi => fastapp}/api/v1/__init__.py | 0 code/function/{fastapi => fastapp}/api/v1/api_v1.py | 2 +- .../{fastapi => fastapp}/api/v1/endpoints/heartbeat.py | 4 ++-- code/function/{fastapi => fastapp}/api/v1/endpoints/sample.py | 4 ++-- code/function/{fastapi => fastapp}/core/__init__.py | 0 code/function/{fastapi => fastapp}/core/config.py | 0 code/function/{fastapi => fastapp}/core/messages.py | 0 code/function/{fastapi => fastapp}/main.py | 4 ++-- code/function/{fastapi => fastapp}/models/__init__.py | 0 code/function/{fastapi => fastapp}/models/heartbeat.py | 0 code/function/{fastapi => fastapp}/models/sample.py | 0 code/function/{fastapi => fastapp}/utils.py | 2 +- code/function/wrapper/__init__.py | 2 +- tests/test_main.py | 2 +- 16 files changed, 10 insertions(+), 10 deletions(-) rename code/function/{fastapi => fastapp}/__init__.py (100%) rename code/function/{fastapi => fastapp}/api/__init__.py (100%) rename code/function/{fastapi => fastapp}/api/v1/__init__.py (100%) rename code/function/{fastapi => fastapp}/api/v1/api_v1.py (80%) rename code/function/{fastapi => fastapp}/api/v1/endpoints/heartbeat.py (76%) rename code/function/{fastapi => fastapp}/api/v1/endpoints/sample.py (77%) rename code/function/{fastapi => fastapp}/core/__init__.py (100%) rename code/function/{fastapi => fastapp}/core/config.py (100%) rename code/function/{fastapi => fastapp}/core/messages.py (100%) rename code/function/{fastapi => fastapp}/main.py (83%) rename code/function/{fastapi => fastapp}/models/__init__.py (100%) rename code/function/{fastapi => fastapp}/models/heartbeat.py (100%) rename code/function/{fastapi => fastapp}/models/sample.py (100%) rename code/function/{fastapi => fastapp}/utils.py (93%) diff --git a/code/function/fastapi/__init__.py b/code/function/fastapp/__init__.py similarity index 100% rename from code/function/fastapi/__init__.py rename to code/function/fastapp/__init__.py diff --git a/code/function/fastapi/api/__init__.py b/code/function/fastapp/api/__init__.py similarity index 100% rename from code/function/fastapi/api/__init__.py rename to code/function/fastapp/api/__init__.py diff --git a/code/function/fastapi/api/v1/__init__.py b/code/function/fastapp/api/v1/__init__.py similarity index 100% rename from code/function/fastapi/api/v1/__init__.py rename to code/function/fastapp/api/v1/__init__.py diff --git a/code/function/fastapi/api/v1/api_v1.py b/code/function/fastapp/api/v1/api_v1.py similarity index 80% rename from code/function/fastapi/api/v1/api_v1.py rename to code/function/fastapp/api/v1/api_v1.py index 488ff98..b5e7276 100644 --- a/code/function/fastapi/api/v1/api_v1.py +++ b/code/function/fastapp/api/v1/api_v1.py @@ -1,5 +1,5 @@ from fastapi import APIRouter -from fastapi.api.v1.endpoints import heartbeat, sample +from fastapp.api.v1.endpoints import heartbeat, sample api_v1_router = APIRouter() api_v1_router.include_router(sample.router, prefix="/sample", tags=["sample"]) diff --git a/code/function/fastapi/api/v1/endpoints/heartbeat.py b/code/function/fastapp/api/v1/endpoints/heartbeat.py similarity index 76% rename from code/function/fastapi/api/v1/endpoints/heartbeat.py rename to code/function/fastapp/api/v1/endpoints/heartbeat.py index c3015be..1f70a61 100644 --- a/code/function/fastapi/api/v1/endpoints/heartbeat.py +++ b/code/function/fastapp/api/v1/endpoints/heartbeat.py @@ -1,8 +1,8 @@ from typing import Any from fastapi import APIRouter -from fastapi.models.heartbeat import HearbeatResult -from fastapi.utils import setup_logging +from fastapp.models.heartbeat import HearbeatResult +from fastapp.utils import setup_logging logger = setup_logging(__name__) diff --git a/code/function/fastapi/api/v1/endpoints/sample.py b/code/function/fastapp/api/v1/endpoints/sample.py similarity index 77% rename from code/function/fastapi/api/v1/endpoints/sample.py rename to code/function/fastapp/api/v1/endpoints/sample.py index 0442916..47439a8 100644 --- a/code/function/fastapi/api/v1/endpoints/sample.py +++ b/code/function/fastapp/api/v1/endpoints/sample.py @@ -1,8 +1,8 @@ from typing import Any from fastapi import APIRouter -from fastapi.models.sample import SampleRequest, SampleResponse -from fastapi.utils import setup_logging +from fastapp.models.sample import SampleRequest, SampleResponse +from fastapp.utils import setup_logging logger = setup_logging(__name__) diff --git a/code/function/fastapi/core/__init__.py b/code/function/fastapp/core/__init__.py similarity index 100% rename from code/function/fastapi/core/__init__.py rename to code/function/fastapp/core/__init__.py diff --git a/code/function/fastapi/core/config.py b/code/function/fastapp/core/config.py similarity index 100% rename from code/function/fastapi/core/config.py rename to code/function/fastapp/core/config.py diff --git a/code/function/fastapi/core/messages.py b/code/function/fastapp/core/messages.py similarity index 100% rename from code/function/fastapi/core/messages.py rename to code/function/fastapp/core/messages.py diff --git a/code/function/fastapi/main.py b/code/function/fastapp/main.py similarity index 83% rename from code/function/fastapi/main.py rename to code/function/fastapp/main.py index de13852..4cc0c51 100644 --- a/code/function/fastapi/main.py +++ b/code/function/fastapp/main.py @@ -1,6 +1,6 @@ from fastapi import FastAPI -from fastapi.api.v1.api_v1 import api_v1_router -from fastapi.core.config import settings +from fastapp.api.v1.api_v1 import api_v1_router +from fastapp.core.config import settings def get_app() -> FastAPI: diff --git a/code/function/fastapi/models/__init__.py b/code/function/fastapp/models/__init__.py similarity index 100% rename from code/function/fastapi/models/__init__.py rename to code/function/fastapp/models/__init__.py diff --git a/code/function/fastapi/models/heartbeat.py b/code/function/fastapp/models/heartbeat.py similarity index 100% rename from code/function/fastapi/models/heartbeat.py rename to code/function/fastapp/models/heartbeat.py diff --git a/code/function/fastapi/models/sample.py b/code/function/fastapp/models/sample.py similarity index 100% rename from code/function/fastapi/models/sample.py rename to code/function/fastapp/models/sample.py diff --git a/code/function/fastapi/utils.py b/code/function/fastapp/utils.py similarity index 93% rename from code/function/fastapi/utils.py rename to code/function/fastapp/utils.py index 4934bac..9f152df 100644 --- a/code/function/fastapi/utils.py +++ b/code/function/fastapp/utils.py @@ -1,7 +1,7 @@ import logging from logging import Logger -from fastapi.core.config import settings +from fastapp.core.config import settings def setup_logging(module) -> Logger: diff --git a/code/function/wrapper/__init__.py b/code/function/wrapper/__init__.py index a52a5a9..b30f269 100644 --- a/code/function/wrapper/__init__.py +++ b/code/function/wrapper/__init__.py @@ -1,5 +1,5 @@ import azure.functions as func -from fastapi.main import app +from fastapp.main import app async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse: diff --git a/tests/test_main.py b/tests/test_main.py index 1fa8ff4..5b6ce37 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,6 @@ import pytest from fastapi.testclient import TestClient -from fastapi.main import fastapi_app +from fastapp.main import fastapi_app @pytest.fixture(scope="module") From e89c01303c003b7b57d10cb718aa5517bfd03f45 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 15:59:52 +0200 Subject: [PATCH 14/27] Update test reference --- tests/test_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 5b6ce37..d9cac8c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,11 +1,11 @@ import pytest from fastapi.testclient import TestClient -from fastapp.main import fastapi_app +from fastapp.main import app @pytest.fixture(scope="module") def client() -> TestClient: - return TestClient(fastapi_app) + return TestClient(app) @pytest.mark.parametrize("version", ("v1",)) From adc5baa786e12b91f886dda5bde639b270f8ab39 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 18:14:52 +0200 Subject: [PATCH 15/27] Add app insights logging to function code --- code/function/fastapp/core/config.py | 5 ++++- code/function/fastapp/utils.py | 14 +++++++++++++- code/function/requirements.txt | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/code/function/fastapp/core/config.py b/code/function/fastapp/core/config.py index f6f33ac..f727f9b 100644 --- a/code/function/fastapp/core/config.py +++ b/code/function/fastapp/core/config.py @@ -1,6 +1,6 @@ import logging -from pydantic import BaseSettings +from pydantic import BaseSettings, Field class Settings(BaseSettings): @@ -10,6 +10,9 @@ class Settings(BaseSettings): API_V1_STR: str = "/v1" LOGGING_LEVEL: int = logging.INFO DEBUG: bool = False + APPLICATIONINSIGHTS_CONNECTION_STRING: str = Field( + default="", env="APPLICATIONINSIGHTS_CONNECTION_STRING" + ) settings = Settings() diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index 9f152df..83578ae 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -2,10 +2,12 @@ from logging import Logger from fastapp.core.config import settings +from opencensus.ext.azure.log_exporter import AzureLogHandler def setup_logging(module) -> Logger: """Setup logging and event handler. + RETURNS (Logger): The logger object to log activities. """ logger = logging.getLogger(module) @@ -17,6 +19,16 @@ def setup_logging(module) -> Logger: logger_stream_handler.setFormatter( logging.Formatter("[%(asctime)s] [%(levelname)s] [%(module)-8.8s] %(message)s") ) - logger.addHandler(logger_stream_handler) + + # Add azure event handler + if settings.APPLICATIONINSIGHTS_CONNECTION_STRING: + azure_log_handler = AzureLogHandler() + azure_log_handler.setFormatter( + logging.Formatter( + "[%(asctime)s] [%(levelname)s] [%(module)-8.8s] %(message)s" + ) + ) + logger.addHandler(azure_log_handler) + return logger diff --git a/code/function/requirements.txt b/code/function/requirements.txt index e380e21..f12a11a 100644 --- a/code/function/requirements.txt +++ b/code/function/requirements.txt @@ -5,3 +5,6 @@ azure-functions~=1.14.0 fastapi~=0.96.1 aiohttp~=3.8.4 +opencensus~=0.11.0 +opencensus-ext-logging~=0.1.1 +opencensus-ext-azure~=1.1.9 From 03bc9e3c42a234f96bad979d189cd79b75211bb1 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 18:45:32 +0200 Subject: [PATCH 16/27] Update logging configuration --- code/function/fastapp/utils.py | 12 ------------ code/function/host.json | 4 ++++ code/function/requirements.txt | 3 --- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index 83578ae..d140f1a 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -2,7 +2,6 @@ from logging import Logger from fastapp.core.config import settings -from opencensus.ext.azure.log_exporter import AzureLogHandler def setup_logging(module) -> Logger: @@ -20,15 +19,4 @@ def setup_logging(module) -> Logger: logging.Formatter("[%(asctime)s] [%(levelname)s] [%(module)-8.8s] %(message)s") ) logger.addHandler(logger_stream_handler) - - # Add azure event handler - if settings.APPLICATIONINSIGHTS_CONNECTION_STRING: - azure_log_handler = AzureLogHandler() - azure_log_handler.setFormatter( - logging.Formatter( - "[%(asctime)s] [%(levelname)s] [%(module)-8.8s] %(message)s" - ) - ) - logger.addHandler(azure_log_handler) - return logger diff --git a/code/function/host.json b/code/function/host.json index 1c14b6a..64b4c08 100644 --- a/code/function/host.json +++ b/code/function/host.json @@ -1,6 +1,10 @@ { "version": "2.0", "logging": { + "fileLoggingMode": "debugOnly", + "logLevel": { + "default": "Information" + }, "applicationInsights": { "samplingSettings": { "isEnabled": true, diff --git a/code/function/requirements.txt b/code/function/requirements.txt index f12a11a..e380e21 100644 --- a/code/function/requirements.txt +++ b/code/function/requirements.txt @@ -5,6 +5,3 @@ azure-functions~=1.14.0 fastapi~=0.96.1 aiohttp~=3.8.4 -opencensus~=0.11.0 -opencensus-ext-logging~=0.1.1 -opencensus-ext-azure~=1.1.9 From 2a10d6d587bf70a97eb914c2f5a3435d5d830604 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:02:26 +0200 Subject: [PATCH 17/27] Update logging --- code/function/fastapp/main.py | 6 ++++++ code/function/fastapp/utils.py | 5 +++++ code/function/requirements.txt | 2 ++ 3 files changed, 13 insertions(+) diff --git a/code/function/fastapp/main.py b/code/function/fastapp/main.py index 4cc0c51..488ef81 100644 --- a/code/function/fastapp/main.py +++ b/code/function/fastapp/main.py @@ -4,6 +4,10 @@ def get_app() -> FastAPI: + """Setup the Fast API server. + + RETURNS (FastAPI): The FastAPI object to start the server. + """ app = FastAPI( title=settings.PROJECT_NAME, version=settings.APP_VERSION, @@ -19,9 +23,11 @@ def get_app() -> FastAPI: @app.on_event("startup") async def startup_event(): + """Gracefully start the application before the server reports readiness.""" pass @app.on_event("shutdown") async def shutdown_event(): + """Gracefully close connections before shutdown of the server.""" pass diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index d140f1a..c97d859 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -2,6 +2,11 @@ from logging import Logger from fastapp.core.config import settings +from opencensus.extension.azure.functions import OpenCensusExtension +from opencensus.trace import config_integration + +config_integration.trace_integrations(["requests"]) +OpenCensusExtension.configure() def setup_logging(module) -> Logger: diff --git a/code/function/requirements.txt b/code/function/requirements.txt index e380e21..727b9a2 100644 --- a/code/function/requirements.txt +++ b/code/function/requirements.txt @@ -5,3 +5,5 @@ azure-functions~=1.14.0 fastapi~=0.96.1 aiohttp~=3.8.4 +opencensus-extension-azure-functions~=1.0.0 +opencensus-ext-requests~=0.8.0 From a467636ae76a174350b8ff95c0bc94eb7fd98ffe Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:06:26 +0200 Subject: [PATCH 18/27] Update logging --- code/function/fastapp/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index c97d859..05e9093 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -5,8 +5,9 @@ from opencensus.extension.azure.functions import OpenCensusExtension from opencensus.trace import config_integration -config_integration.trace_integrations(["requests"]) -OpenCensusExtension.configure() +if settings.APPLICATIONINSIGHTS_CONNECTION_STRING: + config_integration.trace_integrations(["requests"]) + OpenCensusExtension.configure() def setup_logging(module) -> Logger: From d869bbba08a172e3071466273cd6187dbe228736 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:16:52 +0200 Subject: [PATCH 19/27] Update logging --- code/function/fastapp/utils.py | 2 -- code/function/requirements.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index 05e9093..0e3252e 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -3,10 +3,8 @@ from fastapp.core.config import settings from opencensus.extension.azure.functions import OpenCensusExtension -from opencensus.trace import config_integration if settings.APPLICATIONINSIGHTS_CONNECTION_STRING: - config_integration.trace_integrations(["requests"]) OpenCensusExtension.configure() diff --git a/code/function/requirements.txt b/code/function/requirements.txt index 727b9a2..a17289a 100644 --- a/code/function/requirements.txt +++ b/code/function/requirements.txt @@ -6,4 +6,3 @@ azure-functions~=1.14.0 fastapi~=0.96.1 aiohttp~=3.8.4 opencensus-extension-azure-functions~=1.0.0 -opencensus-ext-requests~=0.8.0 From 6cdf8c5024e6af54a3e690b816e7da03c52620f5 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:32:25 +0200 Subject: [PATCH 20/27] Remove opencensus --- code/function/fastapp/utils.py | 4 ---- code/function/requirements.txt | 1 - 2 files changed, 5 deletions(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index 0e3252e..d140f1a 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -2,10 +2,6 @@ from logging import Logger from fastapp.core.config import settings -from opencensus.extension.azure.functions import OpenCensusExtension - -if settings.APPLICATIONINSIGHTS_CONNECTION_STRING: - OpenCensusExtension.configure() def setup_logging(module) -> Logger: diff --git a/code/function/requirements.txt b/code/function/requirements.txt index a17289a..e380e21 100644 --- a/code/function/requirements.txt +++ b/code/function/requirements.txt @@ -5,4 +5,3 @@ azure-functions~=1.14.0 fastapi~=0.96.1 aiohttp~=3.8.4 -opencensus-extension-azure-functions~=1.0.0 From 91d55fd23884c03066f994f046da14bff79b3bc4 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:34:25 +0200 Subject: [PATCH 21/27] Update function app settings --- code/infra/function.tf | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/code/infra/function.tf b/code/infra/function.tf index f62e75e..05e98d5 100644 --- a/code/infra/function.tf +++ b/code/infra/function.tf @@ -70,12 +70,20 @@ resource "azapi_resource" "function" { }, { name = "WEBSITE_RUN_FROM_PACKAGE" - value = "1" + value = "0" }, { name = "PYTHON_ENABLE_WORKER_EXTENSIONS" value = "1" }, + { + name = "ENABLE_ORYX_BUILD" + value = "1" + }, + { + name = "SCM_DO_BUILD_DURING_DEPLOYMENT" + value = "1" + }, { name = "AzureWebJobsStorage__accountName" value = azurerm_storage_account.storage.name @@ -86,9 +94,10 @@ resource "azapi_resource" "function" { functionAppScaleLimit = 0 functionsRuntimeScaleMonitoringEnabled = false ftpsState = "Disabled" + healthCheckPath = var.function_health_path http20Enabled = false ipSecurityRestrictionsDefaultAction = "Deny" - linuxFxVersion = "Python|${var.python_version}" + linuxFxVersion = "Python|${var.function_python_version}" localMySqlEnabled = false loadBalancing = "LeastRequests" minTlsVersion = "1.2" From 25f157a016d33e570e8f60cfeb6df7a2a1b46292 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:34:41 +0200 Subject: [PATCH 22/27] Add health path to variables --- code/infra/variables.tf | 14 ++++++++++++-- code/infra/vars.dev.tfvars | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/code/infra/variables.tf b/code/infra/variables.tf index cd90143..fc69e2a 100644 --- a/code/infra/variables.tf +++ b/code/infra/variables.tf @@ -62,17 +62,27 @@ variable "route_table_id" { } } -variable "python_version" { +variable "function_python_version" { description = "Specifies the python version of the Azure Function." type = string sensitive = false default = "3.10" validation { - condition = contains(["3.9", "3.10"], var.python_version) + condition = contains(["3.9", "3.10"], var.function_python_version) error_message = "Please specify a valid Python version." } } +variable "function_health_path" { + description = "Specifies the health endpoint of the Azure Function." + type = string + sensitive = false + validation { + condition = startswith(var.function_health_path, "/") + error_message = "Please specify a valid path." + } +} + variable "private_dns_zone_id_blob" { description = "Specifies the resource ID of the private DNS zone for Azure Storage blob endpoints. Not required if DNS A-records get created via Azue Policy." type = string diff --git a/code/infra/vars.dev.tfvars b/code/infra/vars.dev.tfvars index 44970b3..d2e9762 100644 --- a/code/infra/vars.dev.tfvars +++ b/code/infra/vars.dev.tfvars @@ -2,7 +2,8 @@ location = "northeurope" environment = "dev" prefix = "myfunc" tags = {} -python_version = "3.10" +function_python_version = "3.10" +function_health_path = "/v1/health/heartbeat" vnet_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/virtualNetworks/mycrp-prd-function-vnet001" nsg_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/networkSecurityGroups/mycrp-prd-function-nsg001" route_table_id = "/subscriptions/8f171ff9-2b5b-4f0f-aed5-7fa360a1d094/resourceGroups/mycrp-prd-function-network-rg/providers/Microsoft.Network/routeTables/mycrp-prd-function-rt001" From 056ad36e311d60e5c8729ca71399877846545d62 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 19:44:35 +0200 Subject: [PATCH 23/27] Propagate logs --- code/function/fastapp/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index d140f1a..1bc654a 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -11,7 +11,7 @@ def setup_logging(module) -> Logger: """ logger = logging.getLogger(module) logger.setLevel(settings.LOGGING_LEVEL) - logger.propagate = False + logger.propagate = True # Create stream handler logger_stream_handler = logging.StreamHandler() From 6ca74bff016fd1ac10099ebe9655bafcabd14fb4 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 20:05:23 +0200 Subject: [PATCH 24/27] Update log categories --- code/function/fastapp/utils.py | 2 +- code/function/host.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/code/function/fastapp/utils.py b/code/function/fastapp/utils.py index 1bc654a..d140f1a 100644 --- a/code/function/fastapp/utils.py +++ b/code/function/fastapp/utils.py @@ -11,7 +11,7 @@ def setup_logging(module) -> Logger: """ logger = logging.getLogger(module) logger.setLevel(settings.LOGGING_LEVEL) - logger.propagate = True + logger.propagate = False # Create stream handler logger_stream_handler = logging.StreamHandler() diff --git a/code/function/host.json b/code/function/host.json index 64b4c08..c2c3e03 100644 --- a/code/function/host.json +++ b/code/function/host.json @@ -3,7 +3,10 @@ "logging": { "fileLoggingMode": "debugOnly", "logLevel": { - "default": "Information" + "default": "Information", + "Host": "Information", + "Function": "Information", + "Host.Aggregator": "Information" }, "applicationInsights": { "samplingSettings": { From 14b19c0c56b5557e02138c3565a2b8854f52539b Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 21:13:58 +0200 Subject: [PATCH 25/27] Add excluded type --- code/function/host.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/function/host.json b/code/function/host.json index c2c3e03..4a75541 100644 --- a/code/function/host.json +++ b/code/function/host.json @@ -11,7 +11,7 @@ "applicationInsights": { "samplingSettings": { "isEnabled": true, - "excludedTypes": "Request" + "excludedTypes": "Request;Exception" } } }, From 2c6ae54b83d2cc4ed02b63cc819a5cc9f794700d Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 21:14:08 +0200 Subject: [PATCH 26/27] Add mpls to infra --- code/infra/logging.tf | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/code/infra/logging.tf b/code/infra/logging.tf index e2576d6..7aaad10 100644 --- a/code/infra/logging.tf +++ b/code/infra/logging.tf @@ -101,3 +101,23 @@ resource "azurerm_monitor_diagnostic_setting" "diagnostic_setting_log_analytics_ } } } + +resource "azurerm_monitor_private_link_scope" "mpls" { + name = "${local.prefix}-ampls001" + resource_group_name = azurerm_resource_group.logging_rg.name + tags = var.tags +} + +resource "azurerm_monitor_private_link_scoped_service" "mpls_application_insights" { + name = "ampls-${azurerm_application_insights.application_insights.name}" + resource_group_name = azurerm_monitor_private_link_scope.mpls.resource_group_name + scope_name = azurerm_monitor_private_link_scope.mpls.name + linked_resource_id = azurerm_application_insights.application_insights.id +} + +resource "azurerm_monitor_private_link_scoped_service" "mpls_log_analytics_workspace" { + name = "ampls-${azurerm_log_analytics_workspace.log_analytics_workspace.name}" + resource_group_name = azurerm_monitor_private_link_scope.mpls.resource_group_name + scope_name = azurerm_monitor_private_link_scope.mpls.name + linked_resource_id = azurerm_log_analytics_workspace.log_analytics_workspace.id +} From 1e34510a899c3fc2c071fa425bcbea9690c653d6 Mon Sep 17 00:00:00 2001 From: Marvin Buss Date: Tue, 13 Jun 2023 21:18:40 +0200 Subject: [PATCH 27/27] Update docs --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 44cc49e..a86d42e 100644 --- a/README.md +++ b/README.md @@ -47,4 +47,12 @@ The deployed services ensure a compliant encryption setup using the following fe ## Azure Function Code -The Azure Function code is written in Python and leverages the new [Web Framework integration](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=asgi%2Capplication-level&pivots=python-mode-decorators#web-frameworks) supported by the v2 Python programming model. +The Azure Function code is written in Python and leverages the new [Web Framework integration](https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=asgi%2Capplication-level&pivots=python-mode-decorators#web-frameworks) supported by the v2 Python programming model. This allows to rely on proven frameworks such as FastAPI and Flask. The Azure Function application code can be found in the [`/code/function` folder](/code/function/). + +## FastAPI + +This sample uses FastAPI as a baseline which is a scalable, modern, fast and proven web framework for APIs built in Python. More details about FastAPI can be found [here](https://fastapi.tiangolo.com/). + +## Testing + +Testing of the Azure Functon application code. The testing is done using `pytest`. Tests are stored in the [`/tests` folder](/tests/) and should be extended for new functionality that is being implemented over time. The `pytest.ini` is used to reference the Azure Functon project for imports. This file makes sure that the respective python objects from the Azrue Function application code can be imported into the tests and validated accordingly.