In my previous post, we walked through how to link an SSL certificate issued by Let's Encrypt, with a custom APEX domain. Throughout this post, I'm going to discuss how to automatically update the A record of a DNS server when the inbound IP address of the Azure Functions instance is changed, update the SSL certificate through the GitHub Actions workflow.
All the GitHub Actions source codes used in this post can be found at this repository.
If you use an Azure Functions instance under Consumption Plan, its inbound IP address is not static. In other words, the inbound IP address of an Azure Functions instance will be changing at any time, without prior notice. Actually, due to the serverless nature, we don't need to worry about the IP address change. If you see the instance details, it has more than one inbound IP address assignable.
Therefore, if you map a custom APEX domain to your Azure Function instance, your APEX domain has to be mapped to an A record of your DNS. And whenever the inbound IP address changes, your DNS must update the A record as well.
If you use Azure PowerShell, you can get the inbound IP address of your Azure Function app instance.
Then, check your DNS and find out the A record. Let's assume that you use Azure DNS service as your DNS. As there can be multiple A records registered, You'll take only the first one for now.
Let's compare to each other. If the inbound IP and the A record are different, update the A record value of Azure DNS.
We've got the A record update done.
If the A record has been updated, the existing SSL certificate is not valid any longer. Therefore, you should also update the SSL certificate. In my previous post, I used the SSL certificate update tool, and it provides the HTTP API endpoint to renew the certificate. Now, you can send the HTTP API request to the endpoint, through PowerShell.
Now, you got the renewed SSL certificate by reflecting the updated A record.
You got the SSL certificate renewed, but your Azure Function instance hasn't got the renewed certificate yet.
According to the doc, the renewed SSL certificate will be automatically synced in 48 hours. If you think it's too long to take, use the following PowerShell script to sync the renewed certificate manually. First of all, get the access token from the login context. If you use the Service Principal, you can get the access token by filtering the client ID of your Service Principal.
Next, get the UNIX timestamp value in milliseconds.
Then, make up the HTTP API endpoint to the certificate. As you've already logged in with your Service Principal, you already know the
Call the endpoint to get the existing certificate details via the
Call the same endpoint with the existing certificate details through the
PUT method. Then, the renewed certificate is synced.
$result object contains the result of the sync process. Both
$result.properties.thumbprint value and
$cert.properties.thumbprint value MUST be different. Otherwise, it's not synced yet. Once the sync process is over, you can find out the renewed thumbprint value on Azure Portal.
Now, we got three jobs for SSL certificate update. Let's build each job as a GitHub Action. By the way, why do I need GitHub Actions for this automation?
- GitHub Actions is not exactly the same, but it has the same nature of serverless – triggered by events and no need to set up the infrastructure.
- Unlike other serverless services, GitHub Actions doesn't need any infrastructure or instance setup or configuration because we only need a repository to run the GitHub Actions workflow.
- GitHub Actions is free of charge, as long as your repository is public (or open-source).
As all GitHub Actions are running Azure PowerShell scripts, we can simply define the common
entrypoint.ps1 file of each Action makes use of the logic stated above.
This is the Action that updates A record on Azure DNS. It returns an output value indicating whether the A record has been updated or not. With this output value, we can decide whether to take further steps or not (line #27, 38).
This is the Action that updates the SSL certificate on Azure Key Vault. It also returns an output value indicating whether the update is successful or not (line #14).
This is the Action that syncs the certificate on Azure Functions. It also returns an output indicating whether the sync is successful or not (line #44).
The ideal way to trigger the GitHub Actions workflow should be the event – when an inbound IP address changes on Azure Function instance, it should raise an event that triggers the GitHub Actions workflow. Unfortunately, at the time of this writing, there is no such event from Azure App Service. Therefore, you should use the scheduler instead. With the timer event of GitHub Actions, you can regularly check the inbound IP address change.
- As the scheduler is the main event trigger, set up the CRON scheduler (line #4-5). Here in the sample code, I run the scheduler for every 30 mins.
- As I use all the actions privately, not publicly, whenever the scheduler is triggered, checkout the code first (line #14-15).
- Update the A record of Azure DNS.
- Depending on the result of the A record update (line #29), it updates the SSL certificate.
- Depending on the result of the SSL certificate renewal (line #37), it syncs the SSL certificate with Azure Functions instance.
- Depending on the result of the SSL certificate sync (line #47), it sends a notification email to administrators.
After the workflow runs, we can see the result like below:
This is the notification email.
If the A record is up-to-date, the workflow stops there and doesn't take the further steps.
So far, we use GitHub Actions workflow to regularly check the inbound IP address of the Azure Functions instance and update the change to Azure DNS, renew an SSL certificate, and sync the certificate with Azure Functions instance. In the next post, I'll discuss how to deploy the Azure Functions app through GitHub Actions without having to know the publish profile.