This article describes an integrated solution for patient records management. A health organization needs to digitally store large amounts of highly sensitive patient medical test data in the cloud. Internal and third-party systems must be able to securely read and write the data through an application programming interface (API). All interactions with the data must be recorded in an audit register.
In this Azure solution, Azure API Management (APIM) controls access to the API through a single managed endpoint. The application backend consists of two interdependent Azure Functions microservice apps that create and manage patient records and audit records. APIM and the two function apps access each other through a locked-down virtual network.
Some benefits of serverless applications like Azure Functions are the cost savings and flexibility of using only necessary compute resources, rather than paying up front for dedicated servers. This solution lets Azure Functions use virtual network access restrictions for security, without incurring the cost and operational overhead of full Azure App Service Environments (ASEs).
This article and the associated code project distill the example scenario down to the main technical components, to serve as scaffolding for specific implementations. The solution automates all code and infrastructure deployments with Terraform, and includes automated integration, unit, and load testing.
Potential use cases
- Access highly sensitive data from designated external endpoints.
- Implement secure auditing for data access operations.
- Integrate interdependent microservices apps with common access and security.
- Use virtual network security features while taking advantage of serverless cost savings and flexibility.
APIM controls internal and third-party access to a set of API microservices built on Azure Functions. The Patient API provides create, read, update, and delete (CRUD) operations for patients and their test results. The Audit API function app provides operations to create auditing entries.
Each function app stores its data in an independent Azure Cosmos DB database. Azure Key Vault securely holds all keys, secrets, and connection strings associated with the apps and databases. Application Insights telemetry and Azure Monitor centralize logging across the system.
The following diagram shows the patient record creation request flow:
- Outside services and clients make a POST request to APIM, with a data body that includes patient information.
- APIM calls the
CreatePatientfunction in the Patient API with the given patient information.
CreatePatientfunction in Patient API calls the
CreateAuditRecordfunction in the Audit API function app to create an audit record.
- The Audit API
CreateAuditRecordfunction creates the audit record in Azure Cosmos DB, and returns a success response to the Patient API
CreatePatientfunction creates the patient document in Azure Cosmos DB, and returns a success response to APIM.
- The outside services and clients receive the success response from APIM.
The solution uses the following components:
Azure API Management (APIM) is a hybrid, multi-cloud platform for managing APIs across all environments. In this solution, APIM controls internal and third-party access to the Patient API that allows reading and/or writing data. APIM allows for easy integration with different authentication mechanisms.
Azure Functions is a serverless compute platform that handles small, event-driven pieces of code. The cloud infrastructure provides the necessary updated servers to run the functions at scale. The current solution uses a set of two Azure Functions API microservices that create and manage operations for patient test results and auditing records.
Azure Virtual Network provides an isolated and highly secure application environment by restricting network access to specific IP addresses or subnets. Both APIM and Azure Functions support access restriction and deployment in virtual networks. This solution uses regional virtual network integration to deploy both function apps in the same virtual network in the same region.
Azure Key Vault centrally stores, encrypts, and manages access to keys, certificates, and connection strings. This solution maintains the Azure Functions host keys and Azure Cosmos DB connection strings in a Key Vault that only specified identities can access.
Azure Cosmos DB is a fully managed serverless database with instant, automatic scaling. In the current solution, both microservices store data in Azure Cosmos DB, using the MongoDB Node.js driver. The services don't share data, and you can deploy each service to its own independent database.
Failures in microservices-based architecture are often distributed over a variety of components, and can't be diagnosed by looking at the services in isolation. The ability to correlate telemetry across components is vital to diagnosing these issues. Application Insights telemetry centralizes logging along the whole request pipeline to detect performance anomalies. The telemetry shares a common operation ID, allowing correlation across components.
APIM and the Azure Functions runtime have built-in support for Application Insights to generate and correlate a wide variety of telemetry, including standard application output. The function apps use the Application Insights Node.js SDK to manually track dependencies and other custom telemetry.
For more information about the distributed telemetry tracing in this solution, see Distributed telemetry.
- The current solution requires a subscription key to access the APIM endpoint, but you can also use Azure Active Directory (Azure AD) authentication.
- In addition to requiring API access keys, you can use Azure Functions' built-in App Service authentication to enable Azure AD authorization for the APIs' managed identities.
- You can replace the Azure Cosmos DB endpoint in this solution with another MongoDB service without changing the code.
- For additional Azure Cosmos DB security, you can lock down traffic from the Azure Cosmos DB databases to the function apps.
- Components such as Azure Cosmos DB can send telemetry to Azure Monitor, where it can be correlated with the telemetry from Application Insights.
- Instead of Terraform, you can use the Azure portal or Azure CLI for Key Vault key rotation tasks.
- Instead of Terraform, you can use a system like Azure DevOps or GitHub Actions to automate solution deployment.
- For higher availability, this solution can be deployed to multiple regions. Set Azure Cosmos DB to multi-master, use APIM's built-in multi-region support, and deploy the Azure Function apps to paired regions.
Consider the following aspects when implementing this solution.
Due to the sensitivity of the data, security is paramount in this solution. The solution uses several mechanisms to protect the data:
- APIM gateway management
- Virtual network access restrictions
- Service access keys and connections strings
- Key and connection string management in Key Vault
- Key Vault key rotation
- Managed service identities
For more details about the security pattern for this solution, see Security pattern for communication between API Management, Functions apps, and Cosmos DB.
API gateway management
The system is publicly accessible only through the single managed APIM endpoint. The APIM subnet restricts incoming traffic to specified gateway node IP addresses.
APIM allows for easy integration with different authentication mechanisms. The current solution requires a subscription key, but you could also use Azure Active Directory to secure the APIM endpoint without needing to manage subscription keys in APIM.
To avoid exposing APIs and functions publicly, Azure Virtual Network restricts network access for APIs and functions to specific IP addresses or subnets. Both API Management and Azure Functions support access restriction and deployment in virtual networks.
Function apps can restrict IPv4, IPv6, and virtual network subnet access. By default, a function app allows all access, but once you add one or more address or subnet restrictions, the app denies all other network traffic.
In this solution, the function apps allow interactions only within their own virtual network. The Patient API allows calls from the APIM subnet by adding the APIM subnet to its access restriction allow list. The Audit API allows communication with the Patient API by adding the Patient API subnet to its access restriction allow list. The APIs reject traffic from other sources.
The solution uses regional virtual network integration to integrate APIM and the function apps with the same virtual network and Azure region. There are several important considerations for using regional virtual network integration:
- You need to use the Azure Functions Premium SKU to have both regional virtual network integration and scalability.
- You need to use the APIM Developer or Premium SKU to enable VNET connectivity
- Since you deploy the function apps in a subnet of the virtual network, you configure the function apps' access restrictions to allow traffic from other subnets in the virtual network.
- Regional virtual network integration only limits outbound traffic from the Azure Function to the virtual network. Inbound traffic is still routed outside of the virtual network, although limited by the app's access list.
Only App Service Environments offer complete network-level virtual network isolation. ASEs can require considerably more expense and effort to implement than Azure Functions that support regional virtual network integration. ASE scaling is also less elastic.
You can call APIM and function apps without using access keys. However, disabling the access keys isn't good security practice, so all components in this solution require keys for access.
- Accessing APIM requires a subscription key, so users need to include
Ocp-Apim-Subscription-Keyin HTTP headers.
- All functions in the Patient API function app require an API access key, so APIM must include
x-functions-keyin the HTTP header when calling the Patient API.
CreateAuditRecordin the Audit API function app requires an API access key, so Patient API needs to include
x-functions-keyin the HTTP header when calling the
- Both Functions apps use Cosmos DB as their data store, so they must use connection strings to access the Cosmos DB databases.
Key Vault storage
Although it's possible to keep access keys and connection strings in the application settings, it's not good practice, because anyone who can access the app can see the keys and strings. The best practice, especially for production environments, is to keep the keys and strings in Azure Key Vault, and use the Key Vault references to call the apps. Key Vault allows access only to specified managed identities.
APIM uses an inbound policy to cache the Patient API host key for improved performance. For subsequent attempts, APIM looks for the key in its cache first.
- APIM retrieves the Patient API host key from Key Vault, caches it, and puts it into an HTTP header when calling the Patient API function app.
- The Patient API function app retrieves the Audit API host key from Key Vault and puts it into an HTTP header when calling the Audit API function app.
- The Azure Function runtime validates the keys in the HTTP headers on incoming requests.
Rotating Key Vault keys helps make the system more secure. You can automatically rotate keys periodically, or you can rotate keys manually or on demand in case of leakage.
Key rotation involves updating several settings:
- The function app host key itself
- The secret in Key Vault that stores the host key
- The Key Vault reference in the function app application settings, to refer to the latest secret version
- The Key Vault reference in the APIM caching policy for the Patient API
The current solution uses Terraform for most of the key rotation tasks. For more information, see Key rotation pattern with Terraform.
In this solution, APIM and the function apps use Azure system-assigned managed service identities (MSIs) to access the Key Vault secrets. Key Vault has the following individual access policies for each service's managed identity:
- APIM can get the host key of the Patient API function app.
- The Patient API function app can get the Audit API host key and the Cosmos DB connection string for its data store.
- The Audit API function app can get the Cosmos DB connection string for its data store.
One of the primary benefits of serverless applications like Azure Functions is the cost savings of paying only for consumption, rather than paying up front for dedicated servers. Virtual network support requires the Azure Functions Premium plan, at additional charge. Azure Functions Premium has support for regional virtual network integration, while still supporting dynamic scaling. The Azure Functions Premium SKU includes virtual network integration on APIM.
For details and pricing calculator, see Azure Functions pricing.
Functions can also be hosted on App Service virtual machines. Only App Service Environments (ASEs) offer complete network-level virtual network isolation. ASEs can be considerably more expensive than an Azure Functions plan that supports regional virtual network integration, and ASE scaling is less elastic.
Deploy the solution
The source code for this solution is at Azure VNet-Integrated Serverless Microservices.
The Typescript source code for the PatientTest API and the Audit API are in the
/src folder. Each API's source includes a dev container that has all the prerequisites installed, to help you get going quickly.
Both APIs have a full suite of automated integration and unit tests to help prevent regressions when you make changes. The project is also configured for linting with ESLint, to maintain code styles and help guard against unintentional errors. The services' respective README files contain information on how to run the tests and linting.
The code project's /env folder includes scripts and templates for Terraform deployment. Terraform deploys APIM and the function apps, and configures them to use the deployed Application Insights instance. Terraform also provisions all resources and configurations, including networking lockdown and the access key security pattern.
The deployment README explains how to deploy the Terraform environment in your own Azure subscription. The
/env folder also includes a dev container that has all the prerequisites installed for Terraform deployment.
Locust load testing
To gauge API performance, you can run load testing against the APIs with the included Locust load tests. Locust is an open-source load testing tool, and the tests are written in Python. You can run the load tests locally, or remotely in an Azure Kubernetes Service (AKS) cluster. The tests perform a variety of operations against the APIM endpoint, and verify behaviors against success and failure criteria.
- Use Azure API Management with microservices deployed in Azure Kubernetes Service
- How to use Azure API Management with virtual networks
- How to use managed identities for App Service and Azure Functions
- Use Key Vault references for App Service and Azure Functions