Trouble with Azure Functions and managed identities

Using Azure Functions managed identity endpoints for TLS certificate automation

While automating TLS certificates for Azure Application Gateways, I ran into an issue with Azure Functions and managed identities. The tool I was using could not fetch a managed identity token. After reviewing its code and the Azure documentation, I found that Azure Functions exposes environment variables for endpoint information that differs slightly from the standard endpoint.

Editor's Note: Please don't take any of this in a negative light. The functionality that would normally be provided by an SDK couldn't be used, and the implementation is uncommon enough that it's understandable a tool like acme.sh wouldn't cover this edge case. It is a great tool, and I'm very happy with it.

I firmly believe that all TLS certificates should be automated. The goal of this project is to request certificates from Let's Encrypt or ZeroSSL and store them in Azure Key Vault for Azure Application Gateway to use. The first problem I hit was managed identity authentication.

The setup

My plan was to run acme.sh in an Azure Function and use Azure's managed identity to authenticate with Azure Key Vault. The function could then store certificates directly in Key Vault for Application Gateway.

Running the Azure Function on a schedule would renew certificates before expiration without manual work.

The problem

Installing acme.sh in the Azure Function was quick, but DNS validation with a managed identity could not fetch a managed identity token.

The error showed that acme.sh could not connect to the managed identity token service. In most Azure environments, services access that token service through a link-local address, typically 169.254.169.254. This endpoint is well documented and widely used, so acme.sh would normally use the correct endpoint.

After connecting to the Azure Function over SSH, I confirmed that it could not reach the metadata endpoint. The Python SDK documentation pointed me to the IDENTITY_ENDPOINT environment variable for the correct endpoint.

The fix

With the correct endpoint and the additional authentication header, I fetched the managed identity token with curl. I then searched acme.sh's code to see how it fetched the token. It made the same hardcoded-endpoint assumption I had, so I put together a small change to fix it.

In the spirit of open-source, and to thank the authors for their work on acme.sh, I was able to send that change as a PR to fix the issue so that no one else would have to go through the same debugging process.

Next steps

I plan to cover the certificate automation for Azure Application Gateway in a later post.