An expired TLS certificate takes production down hard: browsers throw full-page warnings, API clients refuse to connect, and the fix usually happens under pressure at the worst possible time. The frustrating part is that the expiry date was sitting in the certificate all along. Yet if that certificate was uploaded to an Application Gateway listener, an App Service, or an API Management instance, nothing in Azure was going to warn you before the date arrived.
Why Azure cannot alert you out of the box
- Application Gateway listener certificates (bring-your-own) have no native expiry
alerting. The certs you upload to
sslCertificateson an App Gateway just sit there until they lapse. The same goes for thetrustedRootCertificatesused for backend (end-to-end) TLS. - App Service and API Management uploaded certificates expose an expiration date, but
nothing watches it.
Microsoft.Web/certificatesand per-APIM certificates both carry anexpirationDateproperty; it is up to you to read it and act. - The places Azure does alert are not the places most outages come from. Key Vault emits near-expiry Event Grid events for certificates stored there, and Front Door / CDN managed certificates are auto-rotated by Azure. The uncovered stores are exactly the ones where someone uploaded a cert by hand and moved on.
- The App Gateway data is awkward to read even when you go looking. The ARM GET returns the public cert data as base64, and despite the documentation describing it as public cert data corresponding to a pfx, it is actually a PKCS7 (P7B) bundle containing the leaf plus its chain, not a bare X.509 certificate. Naive decoding fails.
The DIY approach: sweep the certificate stores on a schedule
The pattern is a scheduled job (a Function on a timer works well) with a Reader role at subscription scope, sweeping every store that has no native alerting:
- Enumerate App Gateways (Resource Graph makes this fast) and read each one's
properties.sslCertificates[]andproperties.trustedRootCertificates[]. Decode the base64 blobs as PKCS7 first, select the leaf (end-entity) certificate from the bundle, and read itsnotAfter. Fall back to parsing a single DER/PEM certificate for the blobs that are not bundles. - List App Service certificates (
Microsoft.Web/certificates) and per-instance API Management certificates, which already exposeexpirationDatedirectly, so no decoding is needed. - Classify each certificate against your warning thresholds (for example 30, 14, 7, and 1 days) into expired, expiring, or could not read expiry. That last bucket matters: a cert blob that fails to decode is itself a signal worth surfacing.
- Post a digest to Teams (or wherever your on-call lives) and keep reporting an expiring certificate every day until it is renewed, so the alert escalates instead of firing once and getting lost.
Two details keep this least-privilege: read only certificate metadata and public certificate data through the ARM management plane (private keys never need to be touched), and grant nothing beyond Reader.
A ready-made option: Cert Sentinel
Cert Sentinel is that pattern packaged. Every day at 08:00 UTC it sweeps every in-scope certificate in the subscription (App Gateway listener and backend trust certs, App Service uploaded certs, and API Management certs) and posts one digest to your Teams channel listing everything expired, expiring within your thresholds, or unreadable. Expiring certs are re-reported daily until renewed. It needs only the Reader role, reads metadata and public certificate data only (never private keys), and deliberately leaves Key Vault and Front Door / CDN managed certs alone because Azure already covers those.
Key facts
- Native expiry alerting: none for certs uploaded to App Gateway listeners, App Gateway backend trust roots, App Service, or API Management.
- Where Azure does cover you: Key Vault (near-expiry Event Grid events) and Front Door / CDN managed certificates (auto-rotated).
- App Gateway gotcha:
publicCertDatais a PKCS7 (P7B) bundle, not a bare X.509 cert; parse the bundle and take the leaf. - Least privilege: a subscription-scope Reader role is enough; private keys are never read.
- Escalation beats one-shot alerts: report expiring certs daily until renewed.
Related reading: set an Entra ID account to expire automatically.
Written by the team at Katabarwa Labs. We build small, single-purpose Azure tools that run entirely inside your own tenant. Questions: abaho@llmgraph.ai.