fix: add ACME schedule environment variable for Azure Function deployment
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user