The Azure Cloud Resume Challenge in most cases seeks to update a visitor counter when a visitor lands on the resume holder's page.
In my first iteration of the Azure Cloud Resume Challenge I wrote about here, I initially created an architecture that looks like this:
As you can see, my implementation allowed all users to effectively invoke the Azure Function responsible for updating the visit counter in Cosmos DB, directly with Anonymous invocation. There were minor CORS protections added in to the Function App to make sure that responses would only be sent back to browser clients that were running from the desired domain in the form of the CDN endpoint. Regardless, there is a need to acknowledge the sub-optimal practice in the first implementation where the users on their browsers are rather 'too close to the metal' being able to call in directly to the Azure Function.
The Azure Function's duties and visibility can be further abstracted away from the user's browser, and we can do this with an API Gateway inside of an Azure API Management Instance.
From the Azure Portal, I created a new API Management instance on the Developer Tier. Then I imported my existing CosmosReadWriter Azure Function as an API from under the APIM Instance>APIs>Add API>Create from Azure Resource>Function App:
Then each client IP address will be rate limited to prevent too many requests from each client using the Limit Call Rate policy in Inbound Processing:
The API Gateway will enforce a CORS Policy to make sure that browser based requests came from an allowed origin. In my case, I added both the CDN Endpoint where I know users should be coming from and the Blob Storage Origin Endpoint as part of a CORS policy in Inbound Processing:
The API Gateway will add a known custom header key using the Set headers Policy in Inbound Processing to the request before it gets to the backend (the Azure Function), so that the user's browser never gets to know what this key is and is completely blind to any keys or secrets. This key is completely custom and is SEPERATE from the Ocp-Apim-Subscription-Key and can be thought of being a 'stamp of approval' made by the API Gateway itself:
Here, it is also a good idea to purge the CDN under CDN instance Overview>Purge so that the CDN can be re-hydrated with the latest updates from the origin storage container. Otherwise the CDN will use the default content refresh policy, which may not be immediate to take effect for our need.
Finally, the Azure Function code will be updated to become responsible for adding a check for the existence of a specific request header key that is expected to be added by the API Gateway. This key will also be stored in Key Vault. If this expected key is present on the request coming into the Azure Function verified against the same value stored in Key Vault, then the Azure Function can be assured that the request went through the API Gateway and went through the appropriate checks to be granted permission to reach the Azure Function:
The Azure Function code can be updated to look like this instead (other classes):
The entire static web app can now be sending requests to the API Gateway in Azure APIM rather than sending requests directly to the Azure Function.
The new architecture would look like this now: