README
¶
cert-manager-webhook-bunny
Bunny DNS tooling for automated TLS certificate management via ACME DNS-01 challenges. This project provides two ways to use Bunny DNS with ACME:
| Tool | Use case |
|---|---|
| cert-manager webhook | Kubernetes clusters running cert-manager |
bunny-certbot-hook |
Bare-metal / standalone machines running certbot |
Both share the same core DNS logic and are published with every release.
This is a maintained fork of the abandoned gitlab.com/digilol/cert-manager-webhook-bunny project, updated for:
- Go 1.26
- cert-manager v1.20
- Kubernetes 1.29–1.35
- Installable via Helm chart
- Multi-platform image and binaries (linux/amd64 + linux/arm64)
- Distroless runtime (
gcr.io/distroless/static-debian13:nonroot, UID 65532) — no shell, minimal attack surface
Prerequisites
- cert-manager v1.14+ installed in your cluster
- A Bunny.net account with DNS zones managed by Bunny DNS
- Helm 3+
Installation
1. Install the webhook via Helm
From the OCI registry (recommended)
Releases are published automatically to the GitHub Container Registry as OCI artifacts.
| Artifact | OCI reference |
|---|---|
| Helm chart | oci://ghcr.io/cvandesande/charts/cert-manager-webhook-bunny |
| Container image | ghcr.io/cvandesande/cert-manager-webhook-bunny |
Install a specific version:
helm install cert-manager-webhook-bunny \
oci://ghcr.io/cvandesande/charts/cert-manager-webhook-bunny \
--namespace cert-manager \
--create-namespace \
--version 1.0.0
Upgrade to a newer version:
helm upgrade cert-manager-webhook-bunny \
oci://ghcr.io/cvandesande/charts/cert-manager-webhook-bunny \
--namespace cert-manager \
--version 1.0.1
List available chart versions (requires Helm 3.8+, which supports OCI natively):
# pull the latest and inspect
helm show chart oci://ghcr.io/cvandesande/charts/cert-manager-webhook-bunny --version 1.0.0
All releases and their changelogs are listed on the GitHub Releases page.
From source (after cloning)
git clone https://github.com/cvandesande/cert-manager-webhook-bunny.git
cd cert-manager-webhook-bunny
helm install cert-manager-webhook-bunny \
deploy/cert-manager-webhook-bunny \
--namespace cert-manager \
--create-namespace
2. Create a Secret with your Bunny.net API access key
Get your Account API Key from the Bunny.net dashboard (not the zone-specific key).
kubectl create secret generic bunny-credentials \
--from-literal=accessKey=<YOUR_BUNNY_ACCESS_KEY> \
--namespace cert-manager
Note: The Secret must be in the same namespace as the
Issuer, or in any namespace for aClusterIssuer. The webhook service account has read access to secrets cluster-wide.
3. Create an Issuer or ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- dns01:
webhook:
solverName: bunny
groupName: acme.bunny.net
config:
apiSecretRef:
name: bunny-credentials
key: accessKey
4. Request a Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-cert
namespace: default
spec:
secretName: my-cert-tls
dnsNames:
- "example.com"
- "*.example.com"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
Helm Chart Configuration
The following table lists the configurable parameters and their defaults:
| Parameter | Description | Default |
|---|---|---|
image.repository |
Container image repository | ghcr.io/cvandesande/cert-manager-webhook-bunny |
image.tag |
Container image tag (defaults to appVersion when empty) |
"" |
image.pullPolicy |
Image pull policy | IfNotPresent |
replicaCount |
Number of webhook replicas | 1 |
groupName |
ACME DNS01 solver group name | acme.bunny.net |
certManager.namespace |
Namespace where cert-manager is installed | cert-manager |
certManager.serviceAccountName |
cert-manager controller service account name | cert-manager |
resources |
Pod resource requests and limits | {} |
nodeSelector |
Node selector | {} |
tolerations |
Pod tolerations | [] |
affinity |
Pod affinity rules | {} |
Building from Source
# Build the Docker image
make build
# Lint the Helm chart
make helm-lint
# Render the Helm chart to stdout
make rendered-manifest.yaml
Running Tests
The test suite uses cert-manager's DNS01 conformance tests, which:
- Start a temporary in-process Kubernetes API server (envtest)
- Create your credentials Secret inside that cluster
- Call
Presenton the solver — making real API calls to Bunny DNS to create a TXT record - Verify the record is resolvable by querying Bunny's authoritative nameservers directly
- Call
CleanUpto delete the record
Prerequisites
- A real domain managed by Bunny DNS (e.g.
example.com) - Your Bunny.net Account API Key (from dash.bunny.net/account/apikey)
- The kubebuilder test tools (etcd + kube-apiserver) — downloaded automatically by
make
No credential files need to be created — credentials are read entirely from environment variables. The test skips automatically if either variable is unset, making it safe to run in CI without secrets.
Required Environment Variables
| Variable | Description |
|---|---|
BUNNY_ACCESS_KEY |
Your Bunny.net Account API Key |
TEST_ZONE_NAME |
A DNS zone managed in Bunny DNS, with trailing dot (e.g. example.com.) |
Optional Environment Variables
| Variable | Default | Description |
|---|---|---|
TEST_USE_AUTHORITATIVE |
true |
Query the zone's own authoritative nameservers (Bunny's kiki.bunny.net / coco.bunny.net). Records are visible immediately after creation. Set to false to use a public resolver instead. |
TEST_DNS_SERVER |
(none) | Custom DNS server to use when TEST_USE_AUTHORITATIVE=false (e.g. 8.8.8.8:53). |
Running with Go
make test automatically installs setup-envtest and the correct Kubernetes binaries:
export BUNNY_ACCESS_KEY=your-api-key-here
export TEST_ZONE_NAME=example.com.
make test
Running with Docker (no local Go required)
Everything — including downloading depedencies and test binaries — happens inside the container:
make test-docker BUNNY_ACCESS_KEY=your-api-key-here TEST_ZONE_NAME=example.com.
Important Notes
- The test creates and deletes a real
_acme-challengeTXT record in your Bunny DNS zone - In authoritative mode (the default), records are visible immediately on Bunny's nameservers — no propagation delay
- Tests skip gracefully when
BUNNY_ACCESS_KEYorTEST_ZONE_NAMEare not set, so the test suite is safe to run in CI environments that don't have credentials configured
Certbot (bare metal / standalone)
For machines that run certbot directly — without Kubernetes — a small standalone binary is provided: bunny-certbot-hook.
It is used as certbot's --manual-auth-hook and --manual-cleanup-hook to create and remove the DNS-01 challenge TXT records in Bunny DNS automatically.
Download
Pre-built binaries for Linux (amd64 and arm64) are attached to every GitHub Release.
# Example: download the amd64 binary for v1.0.2
curl -L -o /usr/local/bin/bunny-certbot-hook \
https://github.com/cvandesande/cert-manager-webhook-bunny/releases/download/v1.0.2/bunny-certbot-hook-linux-amd64
chmod +x /usr/local/bin/bunny-certbot-hook
Replace amd64 with arm64 on ARM hosts.
Usage
Export your Bunny.net Account API Key (from dash.bunny.net/account/apikey):
export BUNNY_API_KEY=your-api-key-here
Then run certbot with manual DNS hooks:
certbot certonly \
--manual \
--preferred-challenges dns \
--manual-auth-hook "bunny-certbot-hook present" \
--manual-cleanup-hook "bunny-certbot-hook cleanup" \
-d "example.com" \
-d "*.example.com"
Certbot sets CERTBOT_DOMAIN and CERTBOT_VALIDATION automatically before invoking each hook. The binary reads BUNNY_API_KEY from the environment; no config files are required.
Tip: To avoid typing the export every time, add
BUNNY_API_KEY=...to a root-only file (e.g./etc/bunny.env) and source it in the hook call:--manual-auth-hook "source /etc/bunny.env && bunny-certbot-hook present" \ --manual-cleanup-hook "source /etc/bunny.env && bunny-certbot-hook cleanup"
Environment variables
| Variable | Required | Description |
|---|---|---|
BUNNY_API_KEY |
✅ | Bunny.net Account API Key |
CERTBOT_DOMAIN |
set by certbot | Domain being validated (e.g. example.com) |
CERTBOT_VALIDATION |
set by certbot | Value to place in the TXT record |
Build from source
With Go installed (produces ./bunny-certbot-hook for the host architecture):
make build-hook
Without Go (uses Docker; produces ./bunny-certbot-hook-linux-amd64 and ./bunny-certbot-hook-linux-arm64):
make build-hook-docker
Architecture
The webhook implements the cert-manager webhook.Solver interface:
Present– Creates a TXT DNS record in the specified Bunny DNS zone to satisfy the ACME DNS-01 challenge.CleanUp– Deletes the TXT DNS record once the challenge is complete.Initialize– Sets up the Kubernetes client for reading Secrets.
The webhook is registered as a Kubernetes API extension via an APIService resource. cert-manager routes DNS-01 challenge requests to the webhook's API endpoint. TLS for the webhook server is automatically provisioned by cert-manager using a self-signed CA.
License
Documentation
¶
There is no documentation for this package.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
certbot-hook
command
bunny-certbot-hook is a standalone certbot manual-hook binary that manages Bunny.net DNS TXT records for ACME DNS-01 challenges.
|
bunny-certbot-hook is a standalone certbot manual-hook binary that manages Bunny.net DNS TXT records for ACME DNS-01 challenges. |
|
internal
|
|
|
bunnydns
Package bunnydns provides helpers for managing DNS-01 challenge TXT records in Bunny.net DNS zones.
|
Package bunnydns provides helpers for managing DNS-01 challenge TXT records in Bunny.net DNS zones. |