Monitoring App Service certificate expiration dates using Azure Functions
Published: 2023-01-29 13:29:51

On Azure, We can bought TLS/SSL certificate as [App Service Certificate](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate). and it has auto-renew function, so we no need to worry about expiration dates.
other hands, App Service Certificate (=GoDaddy) issue policy require domain verification every 395 days. We need to know when it expires to ensure that we renew our certificates(*1).

*1…App Service Certificate notifies the expiration date (=domain verification require case), but the destination is fixed. for example: if you issue certificate for example.com, Only the following five addresses will be notified.
 - webmaster@example.com
 - hostmaster@example.com
 - postmaster@example.com
 - admin@example.com
 - administrator@example.com

As an alternative, I would like to introduce a system that uses Azure Functions to check the expiration date of certificates and notify by e-mail with sample code.

# Overview of the system
system is very simple. Azure Functions accessing Key Vault and evaluate remaining date.
The evaluation results are notified via email using SendGrid.
Using the [Timer trigger](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp) in Functions, you can check the expiration status periodically, such as once a week or once a month.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8fizegxl00u05luwy7x.png)
processing flow:
(1) Access KeyVault from Azure Functions. Check certificate (secret) expiration date
(2) Create emails with expiration date information categorized into three types: active, expires soon, and expired.
(3) Email notification via SendGrid

The following resources are required to build this mechanism:
- Azure Key Vault (it's contains Certificate)
- Azure Functions
  -- Windows consumption, Runtime v4.x, Node.js 16LTS
  -- If you have a App Service Plan (Standard SKU or Premium), you can able to run this app with same App Service Plan.
- SendGrid: Free 100 (2022) plan, it is able to send 100 mails/day

# Resource creation
Configure the information necessary to create and access each resource.

## Prepare of SendGrid
Create a SendGrid account, obtain an API Key, and register an email address to be used as the sender (Sender Verification).

For information on creating a SendGrid account, please refer to the following document
[Create a Twilio SendGrid account](https://docs.sendgrid.com/for-developers/partners/microsoft-azure-2021#create-a-twilio-sendgrid-account)

For information on obtaining an API Key, please refer to the following document
[API Keys](https://docs.sendgrid.com/for-developers/partners/microsoft-azure-2021#api-keys)
The SendGrid API Key is displayed only once when it is created. Be sure to record it in notepad.

The obtained SendGrid API Key will be registered in the application settings later with the following name.
```
AzureWebJobsSendGridApiKey = SendGrid API Key (example: SG.xxxx...)
```

Lastly, the registration of the email address to be used as the sender (Sender Identity): SendGrid allows you to send email to a specified email address as the sender. However, since there is a problem of spoofing, the email address is registered and verified in advance.
If you have just created a Sendgrid account, the email address to be used as the sender is not registered.
Open [Setup Guide] from the Sendgrid icon in the upper left corner, or go to [Settings] > [Sender Authentication] to register the email address to be used as the sender.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4k9gkc2jvfbogvrebien.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pd0xqzizgvz6vzay2mxn.png)

Enter the email address and sender information to be used as the sender.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvpaj4pj1bj4ps993s9p.png)

When you have completed the form and click the "Create" button, a confirmation e-mail will be sent to the e-mail address you specified as the sender.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mfzqjnwcce22tndvfg46.png)

A confirmation e-mail will be sent to the e-mail address provided. If you recognize it, click the link specified in the [Verify Single Sender] section.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdiaex0gtjjcp70n1tgv.png)

Go to Sendgrid site, and if a confirmation message appears, sender verification is complete.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2oisl02dyi97cinqduj1.png)

The specified e-mail address can now be used as the sender when using Sendgrid.

## Prepare Key Vault
If you are using an App Service certificate, you should have a KeyVault for storage.

If you have no Key Vault resource, [create new Key Vault](https://learn.microsoft.com/ja-jp/azure/key-vault/certificates/quick-create-portal) and create an appropriate self-signed certificate in "Certificate".

## Azure Functions Resource
Create Azure Functions resource. There are several ways to create resources, but we will create a Java Script language, Windows, Consumption plan.
- [Create your first function in the Azure portal](https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-function-app-portal)
- [Quickstart: Create a JavaScript function in Azure using Visual Studio Code](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node)

When creating Azure Functions in an existing App Service Plan, AlwaysOn must be enabled. If AlwaysOn is disabled, mostly functions trigger not work fine. for details please check following documents.
- [Always On](https://learn.microsoft.com/en-us/azure/azure-functions/dedicated-plan#always-on)
- [Investigating and reporting issues with timer triggered functions not firing](https://github.com/Azure/azure-functions-host/wiki/Investigating-and-reporting-issues-with-timer-triggered-functions-not-firing)

## Set Application Settings in Azure Functions
Add SendGrid API keys, etc. to Azure Functions. This sample code reference Application Settings as environment value.
Add the following application settings from the portal's [Configuration] > [Application Settings].

| Name | means |
| ---- | ---- |
| KEYVAULT_NAME | Name of Azure Key Vault |
| EXPIRATION_THRESHOLD_INDAYS | Number of days subject to expiration date warning |
| AzureWebJobsSendGridApiKey | SendGrid API Key. [AzureWebJobsSendGridApiKey is default value](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-sendgrid?tabs=in-process%2Cfunctionsv2&pivots=programming-language-javascript#configuration) |
| SendGrid_email_from | e-mail address. Email from. Confirmed email address for Sender Authentication by Sendgrid. |
| SendGrid_email_to | e-mail address. Email to. if you separated with ','(comma), it is able to specify multiple e-mail address. |

## Enable Managed ID of Azure Functions
Authentication is required to access Azure Key Vault from Azure Functions.
Using Managed ID in this scenario.

The configuration step is as follows:
1. [enable a system-assigned identity](https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Chttp) in Azure Functions.
2. [Granting access rights from Functions in the access policy](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-nonaad#grant-access) in Azure Key Vault.

The permissions required by the Key Vault [Access Plicy] are List and Get Secrets and List and Get Certificates.

# Deploy application code
Sample code are shared in following GitHub repository. Please copy and publish by git clone etc. 
https://github.com/ShogoOhe47/azure-keyvault-secret-expirationdate-checker

If you run code in local development environment, need to set local.settings.json. A sample can be found in [local.settings.sample.json](https://github.com/ShogoOhe47/azure-keyvault-secret-expirationdate-checker/blob/main/local.settings.sample.json).

About deploy codes, local development, Timer Trigger schedule (NCRON expression), please read follow docs.
- [Run the function locally](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-node?tabs=azure-cli%2Cbrowser#run-the-function-locally)
- [Deploy the function project to Azure](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-node?tabs=azure-cli%2Cbrowser#deploy-the-function-project-to-azure)
- [NCRONTAB expressions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=in-process&pivots=programming-language-python#ncrontab-expressions)

# Example of Execution Result
If successfully executed, you will receive the following email.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93ztae8jl75hcdhszec1.png)

You can see Key Vault Secrets and Certificate, Expiration date is near (Days remaining < EXPIRATION_THRESHOLD_INDAYS) or not. The App Service Certificate Resource ID and Common Name of the certificate are also listed, so please refer to them when searching for the target resource.

These formats are written in code. You change the code, able to customize as you like.

# Conclusion
I shared sample code for a mechanism to know the expiration date of certificates managed by Key Vault. I am not a javascript expert, so the logic could use improvement. The data collection, processing, and writing email format is [written as is](https://github.com/ShogoOhe47/azure-keyvault-secret-expirationdate-checker/blob/main/kv-expirationdate-checker/index.js#L124).

I would be happy to help you in your work.