From efa04e886a365e4998a03d033f6951656499a7b8 Mon Sep 17 00:00:00 2001 From: Marc Singer Date: Sat, 21 Feb 2026 08:09:53 +0100 Subject: [PATCH 1/5] chore: upgrade dependencies --- Dockerfile | 2 +- go.mod | 12 ++++++------ go.sum | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index d775442..4092c24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.25.7 AS build +FROM golang:1.26.0 AS build WORKDIR /workspace diff --git a/go.mod b/go.mod index 5053bbd..a834a04 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/proton11/cert-manager-desec-webhook -go 1.25.7 +go 1.26.0 require ( github.com/cert-manager/cert-manager v1.19.3 @@ -51,13 +51,13 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/miekg/dns v1.1.68 // indirect + github.com/miekg/dns v1.1.72 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -88,7 +88,7 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect + golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/net v0.50.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect @@ -99,8 +99,8 @@ require ( golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.42.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect google.golang.org/grpc v1.79.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/go.sum b/go.sum index 625a161..334954e 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/E github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8 h1:NpbJl/eVbvrGE0MJ6X16X9SAifesl6Fwxg/YmCvubRI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8/go.mod h1:mi7YA+gCzVem12exXy46ZespvGtX/lZmD/RLnQhVW7U= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -142,8 +142,8 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= -github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -250,8 +250,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= -golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= @@ -296,10 +296,10 @@ gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0 gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s= +google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= From f62edc6bfe999261e1136c0010d7a3c01974df62 Mon Sep 17 00:00:00 2001 From: Marc Singer Date: Sat, 21 Feb 2026 08:27:36 +0100 Subject: [PATCH 2/5] docs: add the main README --- Dockerfile | 2 +- README.md | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4092c24..892c939 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.26.0 AS build +FROM golang:1.26.0-alpine AS build WORKDIR /workspace diff --git a/README.md b/README.md index 09c4d27..665933a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,157 @@ # Cert Manager DeSEC Webhook +

+ cert-manager project logo +

+ +# Independently maintained ACME webhook for desec.io DNS API + +This solver can be used with [desec.io](https://desec.io) DNS API. The documentation of the API can be found [here](https://desec.readthedocs.io/en/latest/) + +## Requirements +- [go](https://golang.org) => 1.26.0 +- [helm](https://helm.sh/) >= v3.0.0 +- [kuberentes](https://kubernetes.io/) => 1.25.0 +- [cert-manager](https://cert-manager.io/) => 1.19.0 + +## Installation + +### Using helm from local checkout +```bash +helm install \ + -n cert-manager \ + desec-webhook \ + charts/cert-manager-desec-webhook +``` + +### Using public helm chart +```bash +helm install \ + -n cert-manager \ + --version \ + desec-webhook \ + oci://ghcr.io/pr0ton11/charts/cert-manager-desec-webhook +``` + +## Uninstallation + +## Creating an issuer + +Create a secret containing the credentials +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: desec-io-token + namespace: cert-manager +type: Opaque +data: + token: your-key-base64-encoded +``` + +We can also then provide a standardised 'testing framework', or set of +conformance tests, which allow us to validate that a DNS provider works as +expected. +Create a 'ClusterIssuer' or 'Issuer' resource as the following: + +```yaml +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: mail@example.com + + privateKeySecretRef: + name: letsencrypt-staging + + solvers: + - dns01: + webhook: + config: + apiKeySecretRef: + key: token + name: desec-io-token + groupName: acme.pr0ton11.github.com + solverName: desec +``` + +## Create a manual certificate + +```yaml +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: example-cert + namespace: cert-manager +spec: + commonName: example.com + dnsNames: + - example.com + issuerRef: + name: letsencrypt-staging + kind: ClusterIssuer + secretName: example-cert +``` + +## Using cert-manager with traefik ingress +```yaml + +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: bitwarden + namespace: utils + labels: + app: bitwarden + annotations: + cert-manager.io/cluster-issuer: letsencrypt-staging + kubernetes.io/ingress.class: traefik + traefik.ingress.kubernetes.io/rewrite-target: /$1 + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: 'true' +spec: + tls: + - hosts: + - bitwarden.acme.example.com + secretName: bitwarden-crt + rules: + - host: bitwarden.acme.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bitwarden + port: + number: 80 + +``` + +### Creating your own repository + +### Running the test suite + +All DNS providers **must** run the DNS01 provider conformance testing suite, +else they will have undetermined behaviour when used with cert-manager. + +Provide a secret.yaml in testdata/desec + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: desec-token +data: + token: your-key-base64-encoded +type: Opaque +``` + +Define a **TEST_ZONE_NAME** matching to your authenticaton creditials. + +```bash +$ TEST_ZONE_NAME=example.com. make test +``` From 59f3b9a95f4e203dcab83e201705570ba2ea4cb6 Mon Sep 17 00:00:00 2001 From: Marc Singer Date: Sat, 21 Feb 2026 08:36:30 +0100 Subject: [PATCH 3/5] fix: add default test back and use custom solver --- main_test.go | 34 ++++++++++++++++++++++++++++++++++ solver/solver_test.go | 1 - 2 files changed, 34 insertions(+), 1 deletion(-) delete mode 100644 solver/solver_test.go diff --git a/main_test.go b/main_test.go index 06ab7d0..e4ad374 100644 --- a/main_test.go +++ b/main_test.go @@ -1 +1,35 @@ package main + +import ( + "testing" + + acmetest "github.com/cert-manager/cert-manager/test/acme" + + "github.com/proton11/cert-manager-desec-webhook/solver" +) + +func TestRunsSuite(t *testing.T) { + // The manifest path should contain a file named config.json that is a + // snippet of valid configuration that should be included on the + // ChallengeRequest passed as part of the test cases. + // + + // Uncomment the below fixture when implementing your custom DNS provider + //fixture := acmetest.NewFixture(&customDNSProviderSolver{}, + // acmetest.SetResolvedZone(zone), + // acmetest.SetAllowAmbientCredentials(false), + // acmetest.SetManifestPath("testdata/my-custom-solver"), + // acmetest.SetBinariesPath("_test/kubebuilder/bin"), + //) + solver := &solver.DeSECDNSProviderSolver{} + fixture := acmetest.NewFixture(solver, + acmetest.SetResolvedZone("example.com."), + acmetest.SetManifestPath("testdata/desec"), + acmetest.SetDNSServer("127.0.0.1:59351"), + acmetest.SetUseAuthoritative(false), + ) + // need to uncomment and RunConformance delete runBasic and runExtended once https://github.com/cert-manager/cert-manager/pull/4835 is merged + // fixture.RunConformance(t) + fixture.RunBasic(t) + fixture.RunExtended(t) +} diff --git a/solver/solver_test.go b/solver/solver_test.go deleted file mode 100644 index 7434e5e..0000000 --- a/solver/solver_test.go +++ /dev/null @@ -1 +0,0 @@ -package solver_test From 4900f0651fa1fcd2d9223ceb91be6133dfb3c33f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 07:42:20 +0000 Subject: [PATCH 4/5] Initial plan From bb6c67c8ec3e19b1520aeac04b1fdea6e5e12c3b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 07:45:45 +0000 Subject: [PATCH 5/5] Apply review feedback: fix variable shadowing, use TEST_ZONE_NAME env var, fix README typos and solverName Co-authored-by: pr0ton11 <4889380+pr0ton11@users.noreply.github.com> --- README.md | 10 +++++----- main_test.go | 11 ++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 665933a..6dbc6b6 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ This solver can be used with [desec.io](https://desec.io) DNS API. The documentation of the API can be found [here](https://desec.readthedocs.io/en/latest/) ## Requirements -- [go](https://golang.org) => 1.26.0 +- [go](https://golang.org) >= 1.26.0 - [helm](https://helm.sh/) >= v3.0.0 -- [kuberentes](https://kubernetes.io/) => 1.25.0 -- [cert-manager](https://cert-manager.io/) => 1.19.0 +- [kubernetes](https://kubernetes.io/) >= 1.25.0 +- [cert-manager](https://cert-manager.io/) >= 1.19.0 ## Installation @@ -75,7 +75,7 @@ spec: key: token name: desec-io-token groupName: acme.pr0ton11.github.com - solverName: desec + solverName: deSEC ``` ## Create a manual certificate @@ -150,7 +150,7 @@ data: type: Opaque ``` -Define a **TEST_ZONE_NAME** matching to your authenticaton creditials. +Define a **TEST_ZONE_NAME** matching to your authentication credentials. ```bash $ TEST_ZONE_NAME=example.com. make test diff --git a/main_test.go b/main_test.go index e4ad374..9651134 100644 --- a/main_test.go +++ b/main_test.go @@ -1,6 +1,7 @@ package main import ( + "os" "testing" acmetest "github.com/cert-manager/cert-manager/test/acme" @@ -21,9 +22,13 @@ func TestRunsSuite(t *testing.T) { // acmetest.SetManifestPath("testdata/my-custom-solver"), // acmetest.SetBinariesPath("_test/kubebuilder/bin"), //) - solver := &solver.DeSECDNSProviderSolver{} - fixture := acmetest.NewFixture(solver, - acmetest.SetResolvedZone("example.com."), + desecSolver := &solver.DeSECDNSProviderSolver{} + zoneName := os.Getenv("TEST_ZONE_NAME") + if zoneName == "" { + t.Skip("TEST_ZONE_NAME not set") + } + fixture := acmetest.NewFixture(desecSolver, + acmetest.SetResolvedZone(zoneName), acmetest.SetManifestPath("testdata/desec"), acmetest.SetDNSServer("127.0.0.1:59351"), acmetest.SetUseAuthoritative(false),