fix: add ACME schedule environment variable for Azure Function deployment

This commit is contained in:
2026-05-21 16:48:21 +02:00
parent 9c7f9b766f
commit dd53600dfc
+126 -4
View File
@@ -80,6 +80,7 @@ All configuration is via environment variables. CLI flags override env vars when
| `ACME_DNS_PROPAGATION_WAIT` | `60` | Maximum seconds to wait for DNS TXT record propagation | | `ACME_DNS_PROPAGATION_WAIT` | `60` | Maximum seconds to wait for DNS TXT record propagation |
| `ACME_DNS_CHALLENGE_TTL` | `60` | TTL (seconds) for DNS-01 challenge TXT records | | `ACME_DNS_CHALLENGE_TTL` | `60` | TTL (seconds) for DNS-01 challenge TXT records |
| `ACME_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` | | `ACME_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
| `ACME_SCHEDULE` | `0 0 2 * * *` | Azure Function timer schedule (cron expression, 6-field format). Only used when deployed as an Azure Function. |
### Azure Authentication ### Azure Authentication
@@ -95,15 +96,136 @@ For sovereign clouds (Azure Government, Azure China), set `AZURE_AUTHORITY_HOST`
## Azure Function ## Azure Function
The package includes an Azure Functions v4 timer trigger that runs the provisioner daily at 02:00 UTC. To deploy, point the function app at this package's entry point and configure the environment variables above as application settings. The package includes an Azure Functions v4 timer trigger that runs the provisioner daily at 02:00 UTC.
The function app requires a Managed Identity with the following RBAC assignments: The function app requires a Managed Identity with the following RBAC assignments:
| Scope | Role | | Scope | Role |
|---|---| |---|---|
| Key Vault | Key Vault Certificates Officer | | Key Vault instance | Key Vault Certificates Officer |
| Key Vault | Key Vault Secrets Officer | | Key Vault instance | Key Vault Secrets Officer |
| DNS Zone(s) | DNS Zone Contributor | | Each DNS zone | DNS Zone Contributor |
> **Note:** The only DNS changes made are temporary `_acme-challenge.<domain>` TXT records created during the DNS-01 challenge and deleted immediately after validation. No A, CNAME, or other records are modified. If you require tighter permissions than `DNS Zone Contributor`, create a custom role limited to `Microsoft.Network/dnszones/TXT/write` and `Microsoft.Network/dnszones/TXT/delete`.
### Deploying with Azure Functions Core Tools
**Prerequisites:** [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli), [Azure Functions Core Tools v4](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools), Node.js 24.
**1. Log in to Azure**
```sh
az login
```
**2. Create a resource group and storage account** (skip if they already exist)
```sh
az group create --name <resource-group> --location <location>
az storage account create \
--name <storage-account-name> \
--resource-group <resource-group> \
--location <location> \
--sku Standard_LRS
```
**3. Create the Function App**
```sh
az functionapp create \
--name <function-app-name> \
--resource-group <resource-group> \
--storage-account <storage-account-name> \
--consumption-plan-location <location> \
--runtime node \
--runtime-version 24 \
--functions-version 4
```
**4. Assign a system-assigned Managed Identity**
```sh
az functionapp identity assign \
--name <function-app-name> \
--resource-group <resource-group>
```
Note the `principalId` from the output — you will need it in the next step.
**5. Grant RBAC roles to the Managed Identity**
```sh
# Key Vault Certificates Officer
az role assignment create \
--assignee <principalId> \
--role "Key Vault Certificates Officer" \
--scope /subscriptions/<subscription-id>/resourceGroups/<kv-resource-group>/providers/Microsoft.KeyVault/vaults/<keyvault-name>
# Key Vault Secrets Officer
az role assignment create \
--assignee <principalId> \
--role "Key Vault Secrets Officer" \
--scope /subscriptions/<subscription-id>/resourceGroups/<kv-resource-group>/providers/Microsoft.KeyVault/vaults/<keyvault-name>
# Option A — per zone (minimum permission, repeat for each managed DNS zone)
az role assignment create \
--assignee <principalId> \
--role "DNS Zone Contributor" \
--scope /subscriptions/<subscription-id>/resourceGroups/<dns-resource-group>/providers/Microsoft.Network/dnszones/<zone-name>
# Option B — per resource group (convenient when all DNS zones are in one group)
az role assignment create \
--assignee <principalId> \
--role "DNS Zone Contributor" \
--scope /subscriptions/<subscription-id>/resourceGroups/<dns-resource-group>
```
**6. Configure application settings**
```sh
az functionapp config appsettings set \
--name <function-app-name> \
--resource-group <resource-group> \
--settings \
"ACME_KEYVAULT_URL=https://<keyvault-name>.vault.azure.net" \
"ACME_SUBSCRIPTION_ID=<subscription-id>" \
"ACME_RESOURCE_GROUPS=<dns-resource-group>" \
"ACME_CONTACT_EMAIL=<email>"
```
**7. Build and deploy**
```sh
npm run build
func azure functionapp publish <function-app-name>
```
### Local testing
Create a `local.settings.json` file at the project root (it is gitignored):
```json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node",
"ACME_KEYVAULT_URL": "https://<keyvault-name>.vault.azure.net",
"ACME_SUBSCRIPTION_ID": "<subscription-id>",
"ACME_RESOURCE_GROUPS": "<dns-resource-group>",
"ACME_CONTACT_EMAIL": "<email>",
"ACME_SCHEDULE": "0 0 2 * * *"
}
}
```
Then run:
```sh
npm run build
func start
```
## Docker ## Docker