# Azure — Application Gateway, App Service, Front Door

> An Azure Automation runbook fetches the fresh certificate once a day and adds a new version to Key Vault, and Azure services pick it up on their own.

URL: https://zrazu.com/en/docs/ssl-auto-azure/

Use this if your site's certificate is stored in **Azure Key Vault** and used by Application Gateway v2, App Service or Front Door (Standard/Premium). These services switch to a new certificate version in Key Vault by themselves if they are linked "without a version" (Latest): Application Gateway within 4 hours, App Service within a day, Front Door within up to 72 hours.

How it works: a runbook in Azure Automation fetches the certificate from the link once a day, compares it with the current one in Key Vault and, if it is new, builds a PFX with your key (the key is stored in the same Key Vault as a secret) and imports a new version. We get no access to your Azure.

## What you need

- The certificate link from your account: `https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN`.
- A private key without a password, the `key.pem` file. For Front Door, RSA only: Front Door does not accept ECDSA keys.
- A Key Vault with the **Azure role-based access control** permission model and Owner rights on it.

## Step 1. Certificate and key in Key Vault

Open **Cloud Shell** (the `>_` button at the top of the portal, Bash mode), upload `key.pem` (**Manage files → Upload**) and run the commands below, putting in the name of your Key Vault:

```sh
VAULT=KEY_VAULT_NAME
curl -fsS -o fullchain.pem "https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN/fullchain.pem"
az keyvault secret set --vault-name $VAULT --name zrazu-ssl-key --file key.pem
openssl pkcs12 -export -in fullchain.pem -inkey key.pem -out zrazu.pfx -passout pass:
az keyvault certificate import --vault-name $VAULT --name zrazu-ssl --file zrazu.pfx
rm key.pem zrazu.pfx
```

If the certificate is already in Key Vault under another name, skip the last import and change `$CertName` in the runbook (step 3).

Link the certificate to the service without a version if you have not yet: Application Gateway — **Listeners → certificate from Key Vault**; App Service — **Certificates → Bring your own certificates → Import from Key Vault**; Front Door — **Secrets → Add certificate → Latest version**.

## Step 2. Automation account

1. **Automation Accounts → Create** → same resource group and region as the Key Vault → **Review + Create**.
2. In the account, **Account Settings → Identity** → **System assigned: On** → **Save**.
3. In the Key Vault, **Access control (IAM) → Add role assignment**: role **Key Vault Certificates Officer** → **Managed identity** → your Automation account → **Review + assign**. Repeat for the **Key Vault Secrets User** role.

## Step 3. Runbook

1. In the Automation account, **Process Automation → Runbooks → Create a runbook**: name `zrazu-ssl-update`, **Runbook type** PowerShell, **Runtime version** 7.2 → **Create**.
2. Paste the text below, put the Key Vault name in the `$Vault` line → **Save** → **Publish**.

```powershell file=zrazu-azure-runbook.ps1
# ZRAZU: updates the certificate in Azure Key Vault using the personal link. Runs once a day.
$ErrorActionPreference = "Stop"
$Pull = "https://api.zrazu.com/ssl-pull/zsp_YOUR_TOKEN"
$Vault = "KEY_VAULT_NAME"
$CertName = "zrazu-ssl"
$KeySecret = "zrazu-ssl-key"
$X509 = [Security.Cryptography.X509Certificates.X509Certificate2]

Connect-AzAccount -Identity | Out-Null
$full = (Invoke-WebRequest -Uri "$Pull/fullchain.pem" -UseBasicParsing).Content
if ($full -is [byte[]]) { $full = [Text.Encoding]::ASCII.GetString($full) }
$pems = @([regex]::Matches($full, "-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----") | ForEach-Object { $_.Value })
if ($pems.Count -eq 0) { throw "ZRAZU: not a certificate" }
$leaf = $X509::CreateFromPem($pems[0])
$current = Get-AzKeyVaultCertificate -VaultName $Vault -Name $CertName
if ($current -and $current.Thumbprint -eq $leaf.Thumbprint) { "ZRAZU: unchanged"; return }
if ($leaf.NotAfter -le (Get-Date)) { throw "ZRAZU: certificate expired" }
$key = Get-AzKeyVaultSecret -VaultName $Vault -Name $KeySecret -AsPlainText
$withKey = $X509::CreateFromPem($pems[0], $key)
$all = New-Object Security.Cryptography.X509Certificates.X509Certificate2Collection
[void]$all.Add($withKey)
foreach ($pem in ($pems | Select-Object -Skip 1)) { [void]$all.Add($X509::CreateFromPem($pem)) }
$pfx = $all.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12)
Import-AzKeyVaultCertificate -VaultName $Vault -Name $CertName -CertificateString ([Convert]::ToBase64String($pfx)) | Out-Null
"ZRAZU: updated, valid until $($leaf.NotAfter.ToString('yyyy-MM-dd'))"
```

If the key does not match the certificate, `CreateFromPem` stops with an error and nothing is imported.

## Step 4. Schedule

In the runbook, **Link to schedule → Link a schedule to your runbook → Add a schedule**: name `zrazu-daily`, **Recurrence** Recurring, every 1 day, any time at night → **Create** → **OK**.

## Check

1. In the runbook, **Start** → **OK**. Open the job (**Jobs**), **Output** tab: "updated" or "unchanged".
2. In the Key Vault, **Certificates → zrazu-ssl** shows a new version with a new date.
3. Site: [https://zrazu.com/tools/ssl/example.com/](https://zrazu.com/tools/ssl/example.com/) — allowing for how fast your service picks up the new version (see the top of this page).

## If it did not work

- `Forbidden` / `does not have secrets get permission` — one of the two roles from step 2 was not assigned, or the Key Vault uses the access policy model: then in **Access policies** give the identity Certificates: Get, Import and Secrets: Get.
- "The provided key does not match" — the certificate was reissued with a new key: `az keyvault secret set --vault-name $VAULT --name zrazu-ssl-key --file new-key.pem`.
- `404` — the link is disabled or replaced: create a new one in the certificate card and replace `$Pull`.
- Front Door does not take the certificate — the key is ECDSA, or the certificate is linked with a specific version instead of Latest.
