feat: initialize azure-acme-provisioner project with core functionality
- Add package.json for project metadata and dependencies - Implement CLI in src/cli.ts for managing SSL/TLS certificates - Create Azure Functions host configuration in src/function/host.json - Set up timer function in src/function/index.ts for scheduled certificate management - Define configuration loading and error handling in src/lib/config.ts - Implement DNS zone scanning and challenge management in src/lib/dns.ts - Develop ACME client for certificate issuance in src/lib/acme.ts - Create KeyVault store for managing secrets and certificates in src/lib/keyvault.ts - Implement provisioning logic in src/lib/provisioner.ts for issuing and renewing certificates - Add TypeScript configuration files for building the project
This commit is contained in:
@@ -8,3 +8,140 @@ Azure ACME Provisioner is a NodeJS package that provides necessary tools to auto
|
||||
- Stores ACME account information as secrets in Azure KeyVault for secure management.
|
||||
- Stores obtained SSL/TLS certificates in Azure KeyVault for easy access and management.
|
||||
- Automatically scans configured Azure DNS zones to identify records that require certificates (uses the `acme` tag to identify relevant recordsets).
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 24 or later
|
||||
- Azure subscription with:
|
||||
- Azure DNS zone(s) with records tagged `acme: true` or `acme: enabled`
|
||||
- Azure Key Vault instance
|
||||
- Managed Identity (or service principal) with permissions to read/write Key Vault secrets and certificates, and to manage DNS record sets
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install azure-acme-provisioner
|
||||
```
|
||||
|
||||
Or use the CLI directly via `npx`:
|
||||
|
||||
```sh
|
||||
npx azure-acme-provisioner --help
|
||||
```
|
||||
|
||||
## DNS Zone Tagging
|
||||
|
||||
The provisioner discovers domains by scanning Azure DNS zones. Tag a **zone** or individual **A/CNAME recordsets** with `acme: true` to include them:
|
||||
|
||||
- **Zone-level tag** — issues certificates for both the zone apex (`example.com`) and a wildcard (`*.example.com`) as a single SAN order.
|
||||
- **Recordset-level tag** — issues a certificate for that specific FQDN.
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```
|
||||
Commands:
|
||||
run Scan DNS zones and issue or renew certificates (default)
|
||||
scan List all domains tagged for ACME management
|
||||
status Show certificate expiry status for all managed domains
|
||||
renew Force-renew a certificate for a specific domain
|
||||
|
||||
Common options:
|
||||
--keyvault-url <url> Azure KeyVault URL
|
||||
--subscription-id <id> Azure subscription ID
|
||||
--resource-group <rg> Resource group to scan (repeatable)
|
||||
--dns-zone <zone> Restrict to specific DNS zone (repeatable)
|
||||
--email <email> ACME contact email
|
||||
--renewal-threshold <days> Days before expiry to renew (default: 30)
|
||||
--dry-run Show what would be done without making changes
|
||||
--log-level <level> debug | info | warn | error (default: info)
|
||||
--output <format> table | json (scan and status commands)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
All configuration is via environment variables. CLI flags override env vars when both are provided.
|
||||
|
||||
### Required
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `ACME_KEYVAULT_URL` | Azure Key Vault URL, e.g. `https://myvault.vault.azure.net` |
|
||||
| `ACME_SUBSCRIPTION_ID` | Azure subscription ID |
|
||||
| `ACME_RESOURCE_GROUPS` | Comma-separated list of resource groups to scan |
|
||||
| `ACME_CONTACT_EMAIL` | Contact email registered with the ACME CA |
|
||||
|
||||
### Optional
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `ACME_DNS_ZONES` | all zones in resource groups | Comma-separated list of DNS zone names to restrict scanning |
|
||||
| `ACME_DIRECTORY_URL` | Let's Encrypt production | ACME directory URL |
|
||||
| `ACME_RENEWAL_THRESHOLD_DAYS` | `30` | Renew certificates this many days before expiry |
|
||||
| `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_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
||||
|
||||
### Azure Authentication
|
||||
|
||||
The provisioner uses [`DefaultAzureCredential`](https://learn.microsoft.com/en-us/javascript/api/@azure/identity/defaultazurecredential) from `@azure/identity`, which tries authentication methods in this order:
|
||||
|
||||
1. **Managed Identity** — recommended for Azure-hosted deployments (Functions, ACI, AKS). Assign a system or user-assigned managed identity with the required RBAC roles. No credential configuration needed.
|
||||
2. **Workload Identity Federation** — for Kubernetes or CI/CD (GitHub Actions). Set `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_FEDERATED_TOKEN_FILE`. No secrets required.
|
||||
3. **Certificate-based service principal** — set `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_CLIENT_CERTIFICATE_PATH` (optionally `AZURE_CLIENT_CERTIFICATE_PASSWORD`, `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`).
|
||||
4. **Client secret service principal** — set `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_CLIENT_SECRET`. Least secure; use only as a last resort.
|
||||
5. **Azure CLI / Developer CLI** — used automatically in local development when logged in via `az login` or `azd auth login`.
|
||||
|
||||
For sovereign clouds (Azure Government, Azure China), set `AZURE_AUTHORITY_HOST` to the appropriate authority endpoint.
|
||||
|
||||
## 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 function app requires a Managed Identity with the following RBAC assignments:
|
||||
|
||||
| Scope | Role |
|
||||
|---|---|
|
||||
| Key Vault | Key Vault Certificates Officer |
|
||||
| Key Vault | Key Vault Secrets Officer |
|
||||
| DNS Zone(s) | DNS Zone Contributor |
|
||||
|
||||
## Docker
|
||||
|
||||
```sh
|
||||
docker run --rm \
|
||||
-e ACME_KEYVAULT_URL=https://myvault.vault.azure.net \
|
||||
-e ACME_SUBSCRIPTION_ID=<subscription-id> \
|
||||
-e ACME_RESOURCE_GROUPS=my-rg \
|
||||
-e ACME_CONTACT_EMAIL=admin@example.com \
|
||||
ghcr.io/your-org/azure-acme-provisioner
|
||||
```
|
||||
|
||||
When running in Azure Container Instances with a user-assigned Managed Identity, set `AZURE_CLIENT_ID` to the identity's client ID. No other credential variables are needed.
|
||||
|
||||
## Library Usage
|
||||
|
||||
```typescript
|
||||
import { Provisioner, loadConfig } from 'azure-acme-provisioner';
|
||||
|
||||
const config = loadConfig(); // reads from environment variables
|
||||
const provisioner = new Provisioner(config);
|
||||
const result = await provisioner.run();
|
||||
console.log(result);
|
||||
```
|
||||
|
||||
## Certificate Storage
|
||||
|
||||
Certificates are stored as native Azure Key Vault Certificates (PEM format, `application/x-pem-file`), making them available to Azure App Service, API Management, and other Azure services that integrate with Key Vault.
|
||||
|
||||
ACME account credentials (private key and account URL) are stored as Key Vault Secrets and reused across runs.
|
||||
|
||||
Certificate names are derived from the domain: dots are replaced with hyphens, wildcards become `wildcard-`, and a `cert-` prefix is added. For example:
|
||||
|
||||
| Domain | Key Vault certificate name |
|
||||
|---|---|
|
||||
| `api.example.com` | `cert-api-example-com` |
|
||||
| `*.example.com` | `cert-wildcard-example-com` |
|
||||
|
||||
## AI Disclaimer
|
||||
|
||||
The files in this repository may contain code generated by AI tools. While we strive to ensure the quality and security of all code, we recommend reviewing any AI-generated code before using it in production environments.
|
||||
|
||||
Reference in New Issue
Block a user