penguin/webhook-freedns

freedns webhook for cert-manager

commit 1f895be0fe2643c03838b043ce1d622f4024f791

authorJake Sanders <i@am.so-aweso.me>
date2021-02-22T16:02:41Z
subjectTidy example package
commit 1f895be0fe2643c03838b043ce1d622f4024f791
Author: Jake Sanders <i@am.so-aweso.me>
Date:   2021-02-22T16:02:41Z

    Tidy example package
    
    Signed-off-by: Jake Sanders <i@am.so-aweso.me>
---
 Dockerfile         |  3 +-
 example/dns.go     | 88 ++++++++++++++++++++++++++++++------------------------
 example/example.go | 19 ++++++++----
 3 files changed, 63 insertions(+), 47 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index ff380f6..9b49cee 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,8 @@
-FROM golang:1.15-alpine AS build_deps
+FROM golang:1.16-alpine AS build_deps
 
 RUN apk add --no-cache git
 
 WORKDIR /workspace
-ENV GO111MODULE=on
 
 COPY go.mod .
 COPY go.sum .
diff --git a/example/dns.go b/example/dns.go
index 9b00b79..e29597e 100644
--- a/example/dns.go
+++ b/example/dns.go
@@ -2,6 +2,7 @@ package example
 
 import (
 	"fmt"
+
 	"github.com/miekg/dns"
 )
 
@@ -11,45 +12,7 @@ func (e *exampleSolver) handleDNSRequest(w dns.ResponseWriter, req *dns.Msg) {
 	switch req.Opcode {
 	case dns.OpcodeQuery:
 		for _, q := range msg.Question {
-			switch q.Qtype {
-			case dns.TypeA:
-				rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN A 127.0.0.1", q.Name))
-				if err != nil {
-					msg.SetRcode(req, dns.RcodeNameError)
-				} else {
-					msg.Answer = append(msg.Answer, rr)
-				}
-			case dns.TypeTXT:
-				// get record
-				e.RLock()
-				record, found := e.txtRecords[q.Name]
-				e.RUnlock()
-				if !found {
-					msg.SetRcode(req, dns.RcodeNameError)
-				} else {
-					rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN TXT %s", q.Name, record))
-					if err != nil {
-						msg.SetRcode(req, dns.RcodeServerFailure)
-						break
-					}
-					msg.Answer = append(msg.Answer, rr)
-				}
-			case dns.TypeNS:
-				rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN NS ns.example-acme-webook.invalid.", q.Name))
-				if err != nil {
-					msg.SetRcode(req, dns.RcodeServerFailure)
-					break
-				} else {
-					msg.Answer = append(msg.Answer, rr)
-				}
-			case dns.TypeSOA:
-				rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN SOA %s 20 5 5 5 5", "ns.example-acme-webook.invalid.", "ns.example-acme-webook.invalid."))
-				if err != nil {
-					msg.SetRcode(req, dns.RcodeServerFailure)
-					break
-				}
-				msg.Answer = append(msg.Answer, rr)
-			default:
+			if err := e.addDNSAnswer(q, msg, req); err != nil {
 				msg.SetRcode(req, dns.RcodeServerFailure)
 				break
 			}
@@ -57,3 +20,50 @@ func (e *exampleSolver) handleDNSRequest(w dns.ResponseWriter, req *dns.Msg) {
 	}
 	w.WriteMsg(msg)
 }
+
+func (e *exampleSolver) addDNSAnswer(q dns.Question, msg *dns.Msg, req *dns.Msg) error {
+	switch q.Qtype {
+	// Always return loopback for any A query
+	case dns.TypeA:
+		rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN A 127.0.0.1", q.Name))
+		if err != nil {
+			return err
+		}
+		msg.Answer = append(msg.Answer, rr)
+		return nil
+
+	// TXT records are the only important record for ACME dns-01 challenges
+	case dns.TypeTXT:
+		e.RLock()
+		record, found := e.txtRecords[q.Name]
+		e.RUnlock()
+		if !found {
+			msg.SetRcode(req, dns.RcodeNameError)
+			return nil
+		}
+		rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN TXT %s", q.Name, record))
+		if err != nil {
+			return err
+		}
+		msg.Answer = append(msg.Answer, rr)
+		return nil
+
+	// NS and SOA are for authoritative lookups, return obviously invalid data
+	case dns.TypeNS:
+		rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN NS ns.example-acme-webook.invalid.", q.Name))
+		if err != nil {
+			return err
+		}
+		msg.Answer = append(msg.Answer, rr)
+		return nil
+	case dns.TypeSOA:
+		rr, err := dns.NewRR(fmt.Sprintf("%s 5 IN SOA %s 20 5 5 5 5", "ns.example-acme-webook.invalid.", "ns.example-acme-webook.invalid."))
+		if err != nil {
+			return err
+		}
+		msg.Answer = append(msg.Answer, rr)
+		return nil
+	default:
+		return fmt.Errorf("unimplemented record type %v", q.Qtype)
+	}
+}
diff --git a/example/example.go b/example/example.go
index 49eca8f..d31b42d 100644
--- a/example/example.go
+++ b/example/example.go
@@ -3,6 +3,8 @@
 package example
 
 import (
+	"fmt"
+	"os"
 	"sync"
 
 	"github.com/jetstack/cert-manager/pkg/acme/webhook"
@@ -18,31 +20,36 @@ type exampleSolver struct {
 	sync.RWMutex
 }
 
-func (e exampleSolver) Name() string {
+func (e *exampleSolver) Name() string {
 	return e.name
 }
 
-func (e exampleSolver) Present(ch *acme.ChallengeRequest) error {
+func (e *exampleSolver) Present(ch *acme.ChallengeRequest) error {
 	e.Lock()
 	e.txtRecords[ch.ResolvedFQDN] = ch.Key
 	e.Unlock()
 	return nil
 }
 
-func (e exampleSolver) CleanUp(ch *acme.ChallengeRequest) error {
+func (e *exampleSolver) CleanUp(ch *acme.ChallengeRequest) error {
 	e.Lock()
 	delete(e.txtRecords, ch.ResolvedFQDN)
 	e.Unlock()
 	return nil
 }
 
-func (e exampleSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
+func (e *exampleSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
 	go func(done <-chan struct{}) {
 		<-done
-		e.server.Shutdown()
+		if err := e.server.Shutdown(); err != nil {
+			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
+		}
 	}(stopCh)
 	go func() {
-		e.server.ListenAndServe()
+		if err := e.server.ListenAndServe(); err != nil {
+			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
+			os.Exit(1)
+		}
 	}()
 	return nil
 }