A storage module to use Azure Blob Storage as key/certificate storage backend for your Certmagic-enabled HTTPS server.
Inspired by grafana/certmagic-gcs.
Recommendations to enhance security:
- Enable infrastructure encryption during storage account creation for double encryption at rest.
- Use customer-managed keys for storage service encryption and leverage Key Vault key rotation policy.
- Apply least privilege RBAC controls - grant only the minimum required permissions (e.g.,
Storage Blob Data Contributorfor the container). - Use managed identity authentication where possible and disable storage account key access.
- Apply storage account network restrictions - configure firewalls, virtual networks, or private endpoints to limit access.
- Enable blob versioning and soft delete to protect against accidental deletion or corruption of certificates.
- Monitor access with Azure Storage Analytics and set up alerts for unusual access patterns.
In this section, we create a Caddy config using our Azure Blob Storage backend.
-
Set up Azure Storage Account
- Create an Azure Storage Account
- Create a blob container (e.g.,
caddy-data)- The module will create the container if it doesn't exist and has enough permissions
- Get your connection string or configure authentication
-
Create a
Caddyfile{ storage azureblob { account_name YOUR_STORAGE_ACCOUNT container_name caddy-data connection_string "YOUR_STORAGE_CONNECTION_STRING" } } localhost respond "Hello Caddy with Azure Blob Storage!" -
Alternative: Using Managed Identity (recommended for Azure VMs)
{ storage azureblob { account_name myaccount container_name caddy-data # connection_string omitted - will use managed identity } } localhost respond "Hello Caddy with Azure Blob Storage!" -
Start Caddy
xcaddy runor
dotenv run xcaddy run -
Check that it works
curl https://localhost
For local development, you can use Azurite (Azure Storage Emulator):
-
Start Azurite
If using VSCode the simplest way to use Azurite is the Azurite extension
-
Use development connection string
{ storage azureblob { account_name YOUR_AZURITE_ACCOUNT container_name caddy-data connection_string "YOUR_AZURITE_CONNECTION_STRING" } } localhost respond "Hello Caddy with Azurite!"
This module supports several Azure authentication methods:
-
Connection String (Simple)
{ storage azureblob { account_name YOUR_STORAGE_ACCOUNT container_name caddy-data connection_string "YOUR_STORAGE_CONNECTION_STRING" } } -
Managed Identity (Recommended for Azure VMs)
{ storage azureblob { account_name YOUR_STORAGE_ACCOUNT container_name caddy-data } } -
Service Principal (SPN)
Service principal authentication is supported through Azure's default credential chain. Assign the SPN the
Storage Blob Data Contributorrole on the storage account or container, then set its credentials:export AZURE_TENANT_ID="YOUR_TENANT_ID" export AZURE_CLIENT_ID="YOUR_CLIENT_ID" export AZURE_CLIENT_SECRET="YOUR_CLIENT_SECRET"
Configure the storage account and container in your
Caddyfile; leave outconnection_string:{ storage azureblob { account_name YOUR_STORAGE_ACCOUNT container_name caddy-data } } -
Environment Variables
Set these environment variables:
$ export AZURE_STORAGE_ACCOUNT="myaccount" $ export AZURE_STORAGE_CONNECTION_STRING="......" # Or for managed identity: $ export AZURE_CLIENT_ID="......" # Optional: for user assigned identity
The AZURE_CLIENT_ID variable is optional and can be used to supply the client id for a user assigned managed identity. If omitted it will use a system assigned identity by default.
| Parameter | Description | Required |
|---|---|---|
account_name |
Azure Storage Account name | Yes |
container_name |
Blob container name for storing certificates | Yes |
connection_string |
Azure Storage connection string | No* |
*When connection_string is omitted, the module will attempt to use:
- Azure Managed Identity (if running on Azure)
- Environment variables (
AZURE_STORAGE_ACCOUNT,AZURE_STORAGE_CONNECTION_STRING) - Azure CLI credentials
- Default Azure credential chain
Recommended command set (same pattern used in CI) to keep regressions visible:
# 1) Focused lock/lease regressions
go test ./... -v -count=1 -timeout=120s -run 'Test(CertMagicDistributedLocking|LockingOperations|LeaseBasedConcurrentLocking|LockLeaseExpiration)$'
# 2) Full suite, uncached
go test ./... -v -count=1 -timeout=180s
# 3) Race detector
go test ./... -race -count=1 -timeout=240sThe tests support multiple authentication methods, mirroring the behavior of the real module:
-
Install and start Azurite (Azure Storage Emulator)
-
Configure connection string:
cp .env.example .env # Edit .env and uncomment the AZURE_STORAGE_CONNECTION_STRING line # Use the default Azurite connection string provided in the file
-
Run tests:
go test ./...
-
Create
.envfile:cp .env.example .env
-
Edit
.envwith your real Azure Storage credentials:AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=YOUR_ACCOUNT;AccountKey=YOUR_KEY;EndpointSuffix=core.windows.net AZURE_STORAGE_ACCOUNT=YOUR_ACCOUNT
-
Run tests:
go test ./...
-
Login to Azure CLI:
az login
-
Set only the account name:
echo "AZURE_STORAGE_ACCOUNT=your-account-name" > .env # Note: No AZURE_STORAGE_CONNECTION_STRING needed!
-
Run tests:
go test ./...Tests will automatically use your Azure CLI credentials.
With Connection String:
# Windows (PowerShell)
$env:AZURE_STORAGE_CONNECTION_STRING = "DefaultEndpointsProtocol=https;AccountName=..."
$env:AZURE_STORAGE_ACCOUNT = "your-account-name"
go test ./...# Linux/macOS
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=..."
export AZURE_STORAGE_ACCOUNT="your-account-name"
go test ./...With Azure CLI (after az login):
# Windows (PowerShell)
$env:AZURE_STORAGE_ACCOUNT = "your-account-name"
go test ./...# Linux/macOS
export AZURE_STORAGE_ACCOUNT="your-account-name"
go test ./...This module was created by adapting the excellent grafana/certmagic-gcs Google Cloud Storage implementation for Azure Blob Storage. Their Google Cloud Storage implementation was an invaluable reference for understanding the CertMagic storage interface and building a robust storage backend. 🙏
This module is distributed under AGPL-3.0-only.