diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..df618a6 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,43 @@ +name: 'Build docker image' + +on: + push: + branches: + - main + +jobs: + build: + name: "Build" + runs-on: ubuntu-latest + steps: + - name: "Checkout sources" + uses: actions/checkout@v6 + - name: "Login to docker registry" + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: "Set version container labels" + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/pr0ton11/cert-manager-desec-webhook + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=sha + labels: | + maintainer=proton11@github.com + org.opencontainers.image.title=cert-manager-deSEC-webhook + org.opencontainers.image.description=An independently maintained deSEC DNS validation webhook for cert-manager + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: "Build docker image" + uses: docker/build-push-action@v6 + with: + context: . + push: true + platforms: linux/amd64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/go.mod b/go.mod index a763c8f..5053bbd 100644 --- a/go.mod +++ b/go.mod @@ -57,6 +57,7 @@ require ( 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/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,6 +89,7 @@ require ( 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/mod v0.33.0 // indirect golang.org/x/net v0.50.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/sync v0.19.0 // indirect @@ -95,6 +97,7 @@ require ( golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect 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 diff --git a/go.sum b/go.sum index d573a04..625a161 100644 --- a/go.sum +++ b/go.sum @@ -142,6 +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/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= diff --git a/solver/solver.go b/solver/solver.go index 37075b8..f8febd3 100644 --- a/solver/solver.go +++ b/solver/solver.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "fmt" + "strings" acme "github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" v1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + "github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util" "github.com/nrdcg/desec" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -71,6 +73,29 @@ func (s *DeSECDNSProviderSolver) Present(req *acme.ChallengeRequest) error { if err != nil { return err } + zone := util.UnFqdn(req.ResolvedZone) + fqdn := util.UnFqdn(req.ResolvedFQDN) + // Cut the zone from the fqdn to retrieve the subdomain + subdomain := util.UnFqdn(strings.Replace(fqdn, zone, "", 0)) + // Check if zone is managed in deSEC + domain, err := apiClient.Domains.Get(context.Background(), zone) + if err != nil { + return fmt.Errorf("domain %s could not be retrieved from deSEC API: %w", zone, err) + } + // Create the TXT record to be created + recordSet := desec.RRSet{ + Domain: domain.Name, + SubName: subdomain, + Records: []string{fmt.Sprintf("\"%s\"", req.Key)}, + Type: "TXT", + TTL: 3600, + } + // Create the TXT record + _, err = apiClient.Records.Create(context.Background(), recordSet) + if err != nil { + return fmt.Errorf("DNS record %s creation failed: %w", fqdn, err) + } + // Return no error return nil } @@ -81,6 +106,21 @@ func (s *DeSECDNSProviderSolver) CleanUp(req *acme.ChallengeRequest) error { if err != nil { return err } + zone := util.UnFqdn(req.ResolvedZone) + fqdn := util.UnFqdn(req.ResolvedFQDN) + // Cut the zone from the fqdn to retrieve the subdomain + subdomain := util.UnFqdn(strings.Replace(fqdn, zone, "", 0)) + // Check if zone is managed in deSEC + domain, err := apiClient.Domains.Get(context.Background(), zone) + if err != nil { + return fmt.Errorf("domain %s could not be retrieved from deSEC API: %w", zone, err) + } + // Delete the TXT record + err = apiClient.Records.Delete(context.Background(), domain.Name, subdomain, "TXT") + if err != nil { + return fmt.Errorf("DNS record %s deletion failed: %w", fqdn, err) + } + // Return no error return nil } @@ -93,6 +133,6 @@ func (s *DeSECDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopC } // Assign the k8s client to the solver s.k8s = k8s - + // Return no error return nil }