Activates the previously-templated `letsencrypt-dns01-prod` ClusterIssuer
in bp-cert-manager by shipping the missing piece — a Go binary that
satisfies cert-manager's external webhook contract
(`webhook.acme.cert-manager.io/v1alpha1`) against the Dynadot api3.json.
Architecture
============
* `core/pkg/dynadot-client/` — canonical Dynadot HTTP client (shared with
pool-domain-manager and catalyst-dns). Encapsulates the api3.json
transport, command builders, response decoding, and the safe
read-modify-write semantics required to never accidentally wipe a
zone (memory: feedback_dynadot_dns.md). Destructive `set_dns2`
variant is unexported.
* `core/cmd/cert-manager-dynadot-webhook/` — the cert-manager webhook
binary. Implements `Solver.Present` via the client's append-only
`AddRecord` path and `Solver.CleanUp` via the read-modify-write
`RemoveSubRecord` path. Domain allowlist (`DYNADOT_MANAGED_DOMAINS`)
rejects challenges for unmanaged apexes BEFORE any Dynadot call.
* `platform/cert-manager-dynadot-webhook/` — Catalyst-authored Helm
wrapper. Templates Deployment + Service + APIService + serving
Certificate (CA chain via cert-manager Issuer self-signing) +
RBAC + ServiceAccount. Mirrors the standard cert-manager external-
webhook deployment shape.
* `platform/cert-manager/chart/` — flips `dns01.enabled: true` so the
paired ClusterIssuer activates. The interim http01 issuer remains
templated as the rollback path.
Test results
============
core/pkg/dynadot-client — 7 tests PASS (race-clean)
core/cmd/cert-manager-dynadot-... — 9 tests PASS (race-clean)
Test coverage includes a Present/CleanUp round-trip against an
httptest fixture that models Dynadot's zone state, an explicit
unmanaged-domain rejection, a regression preserving a pre-existing
CNAME across the DNS-01 round-trip (the zone-wipe defence), and a
typed-error propagation test that surfaces `ErrInvalidToken` to
cert-manager so the controller will retry.
Helm template smoke render
==========================
`helm template` against the new chart with default values yields 12
resources / 424 lines (APIService, Certificate, ClusterRoleBinding,
Deployment, Issuer, Role, RoleBinding, Service, ServiceAccount). The
modified bp-cert-manager chart still renders both ClusterIssuers
(`letsencrypt-dns01-prod` + `letsencrypt-http01-prod`) with default
values; flipping `certManager.issuers.dns01.enabled=false` is the
clean rollback.
Smoke command (post-deploy)
===========================
kubectl get apiservices.apiregistration.k8s.io \
v1alpha1.acme.dynadot.openova.io
# Issue a *.<sovereign>.<pool> wildcard cert and watch the
# Order/Challenge progress through cert-manager.
CI
==
`.github/workflows/build-cert-manager-dynadot-webhook.yaml` mirrors the
pool-domain-manager-build pattern (cosign keyless signing, SBOM
attestation, GHCR push at `ghcr.io/openova-io/openova/cert-manager-
dynadot-webhook:<sha>`). Triggered by changes to either the binary or
the shared dynadot-client package.
Closes #159
Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
34 lines
1.4 KiB
YAML
34 lines
1.4 KiB
YAML
apiVersion: catalyst.openova.io/v1alpha1
|
|
kind: Blueprint
|
|
metadata:
|
|
name: bp-cert-manager-dynadot-webhook
|
|
labels:
|
|
catalyst.openova.io/section: pts-3-3-security-and-policy
|
|
spec:
|
|
version: 1.0.0
|
|
card:
|
|
title: cert-manager-dynadot-webhook
|
|
summary: |
|
|
cert-manager DNS-01 external webhook for Dynadot. Lets the
|
|
letsencrypt-dns01-prod ClusterIssuer (in bp-cert-manager) issue
|
|
wildcard TLS certificates (e.g. *.<sovereign>.<pool>) by
|
|
provisioning ACME challenge TXT records on the per-Sovereign apex
|
|
via the Dynadot api3.json. Closes openova#159.
|
|
visibility: unlisted # mandatory infra, auto-installed by bootstrap kit
|
|
manifests:
|
|
chart: ./chart
|
|
depends:
|
|
# bp-cert-manager registers the cert-manager.io CRDs and deploys the
|
|
# controllers; this webhook is meaningless without them. Per the
|
|
# waterfall locked in by docs/INVIOLABLE-PRINCIPLES.md (intra-chart
|
|
# CRD ordering) this chart MUST be installed AFTER bp-cert-manager
|
|
# is Ready — Flux dependsOn enforces that at the HelmRelease level.
|
|
- bp-cert-manager
|
|
outputs:
|
|
# Tells dependents (bp-cilium-gateway's wildcard Certificate, etc.)
|
|
# which solverName the ClusterIssuer's solvers[].dns01.webhook
|
|
# block must reference. Defaults are baked into the chart values
|
|
# but exposing them here keeps the blueprint DAG's contract honest.
|
|
solverName: dynadot
|
|
groupName: acme.dynadot.openova.io
|