diff --git a/cert-manager-pdns.gocd.yaml b/cert-manager-pdns.gocd.yaml deleted file mode 100644 index fe4aab3..0000000 --- a/cert-manager-pdns.gocd.yaml +++ /dev/null @@ -1,31 +0,0 @@ -format_version: 10 -pipelines: - cert-manager-pdns: - group: sample - label_template: ${COUNT} - lock_behavior: none - display_order: -1 - materials: - git-5f4a6fb: - git: https://github.com/Timdawson264/cert-manager-pdns.git - shallow_clone: false - auto_update: true - branch: master - stages: - - Build: - fetch_materials: true - keep_artifacts: false - clean_workspace: false - approval: - type: success - allow_only_on_success: false - jobs: - Build: - timeout: 0 - tasks: - - exec: - arguments: - - build - - . - command: go - run_if: passed diff --git a/go.mod b/go.mod index 284f99a..55bb7cc 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/cert-manager/webhook-example +module github.com/Timdawson264/cert-manager-pdns go 1.13 diff --git a/main.go b/main.go index a952041..9ef5ab8 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,6 @@ type customDNSProviderSolver struct { // 4. ensure your webhook's service account has the required RBAC role // assigned to it for interacting with the Kubernetes APIs you need. //client kubernetes.Clientset - pdns *powerdns.Client } // customDNSProviderConfig is a structure that is used to decode into when @@ -97,14 +96,42 @@ func (c *customDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error { } // TODO: do something more useful with the decoded configuration - fmt.Printf("Decoded configuration Key: %s, Server: %s\n", cfg.APIKey, cfg.Server) + //fmt.Printf("Decoded configuration Key: %s, Server: %s\n", cfg.APIKey, cfg.Server) fmt.Printf("Presenting Record zone: %s, fqdn: %s, key: %s\n", ch.ResolvedZone, ch.ResolvedFQDN, ch.Key) //TODO: get a client using a secret + kubeapi - c.pdns = powerdns.NewClient(cfg.Server, "", map[string]string{"X-API-Key": cfg.APIKey}, nil) - err = c.pdns.Records.Add(ch.ResolvedZone, ch.ResolvedFQDN, powerdns.RRTypeTXT, 10, []string{fmt.Sprintf(`"%s"`, ch.Key)}) + pdns := powerdns.NewClient(cfg.Server, "", map[string]string{"X-API-Key": cfg.APIKey}, nil) + + //First Request RRSet and check if key+value exists. else add and set as new rrset. + zone, err := pdns.Zones.Get(ch.ResolvedZone) if err != nil { - fmt.Printf("Error Adding Record: %v\n", err) + fmt.Printf("Error Getting Zone: %v\n", err) + return err + } + + existing_keys := []string{} + + //Try find an Exsisting RRset - and record all the values. + for _, r := range zone.RRsets { + + if *r.Name == ch.ResolvedFQDN && *r.Type == powerdns.RRTypeTXT { + //check if the Record is already in the RRSET + for _, record := range r.Records { + if *record.Content == fmt.Sprintf(`"%s"`, ch.Key) { + fmt.Printf("Challange Already in TXT Record. \n") + return nil + } + existing_keys = append(existing_keys, *record.Content) + } + + } + } + + //Add the new key + existing_keys = append(existing_keys, fmt.Sprintf(`"%s"`, ch.Key)) + err = pdns.Records.Change(ch.ResolvedZone, ch.ResolvedFQDN, powerdns.RRTypeTXT, 15, existing_keys) + if err != nil { + fmt.Printf("Error Adding Record: %+v\n", err) return err } @@ -124,11 +151,31 @@ func (c *customDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { } //TODO: get a client using a secret + kubeapi - c.pdns = powerdns.NewClient(cfg.Server, "", map[string]string{"X-API-Key": cfg.APIKey}, nil) - - //TODO: check value before delete. for parrallel validation - err = c.pdns.Records.Delete(ch.ResolvedZone, ch.ResolvedFQDN, powerdns.RRTypeTXT) + pdns := powerdns.NewClient(cfg.Server, "", map[string]string{"X-API-Key": cfg.APIKey}, nil) + zone, err := pdns.Zones.Get(ch.ResolvedZone) if err != nil { + fmt.Printf("Error Getting Zone: %v\n", err) + return err + } + + remaining_keys := []string{} + + //Make a list of keys that should remain after this cleanup + for _, r := range zone.RRsets { + if *r.Name == ch.ResolvedFQDN && *r.Type == powerdns.RRTypeTXT { + for _, record := range r.Records { + //Remove the matching key + if *record.Content != fmt.Sprintf(`"%s"`, ch.Key) { + remaining_keys = append(remaining_keys, *record.Content) + } + } + + } + } + + err = pdns.Records.Change(ch.ResolvedZone, ch.ResolvedFQDN, powerdns.RRTypeTXT, 15, remaining_keys) + if err != nil { + fmt.Printf("Error Removing Record: %v\n", err) return err } diff --git a/main_test.go b/main_test.go index 0377170..b30fcb3 100644 --- a/main_test.go +++ b/main_test.go @@ -5,8 +5,6 @@ import ( "testing" "github.com/jetstack/cert-manager/test/acme/dns" - - "github.com/cert-manager/webhook-example/example" ) var ( @@ -20,21 +18,24 @@ func TestRunsSuite(t *testing.T) { // // Uncomment the below fixture when implementing your custom DNS provider - //fixture := dns.NewFixture(&customDNSProviderSolver{}, - // dns.SetResolvedZone(zone), - // dns.SetAllowAmbientCredentials(false), - // dns.SetManifestPath("testdata/my-custom-solver"), - // dns.SetBinariesPath("_test/kubebuilder/bin"), - //) - - solver := example.New("59351") - fixture := dns.NewFixture(solver, - dns.SetResolvedZone("example.com."), + fixture := dns.NewFixture(&customDNSProviderSolver{}, + dns.SetResolvedZone(zone), + dns.SetAllowAmbientCredentials(false), dns.SetManifestPath("testdata/my-custom-solver"), dns.SetBinariesPath("_test/kubebuilder/bin"), - dns.SetDNSServer("127.0.0.1:59351"), + dns.SetDNSServer("127.0.0.1:53"), dns.SetUseAuthoritative(false), + dns.SetStrict(true), ) - fixture.RunConformance(t) + + // solver := example.New("59351") + // fixture := dns.NewFixture(solver, + // dns.SetResolvedZone("example.com."), + // dns.SetManifestPath("testdata/my-custom-solver"), + // dns.SetBinariesPath("_test/kubebuilder/bin"), + // dns.SetDNSServer("127.0.0.1:59351"), + // dns.SetUseAuthoritative(false), + // ) + } diff --git a/starttest.sh b/starttest.sh new file mode 100755 index 0000000..56a2f9c --- /dev/null +++ b/starttest.sh @@ -0,0 +1,34 @@ +#!/bin/bash + + +# A really bad test powerdns setup. going to deploy a proper test pod using jenkins later + +docker run -d \ + --name pdns-mysql \ + -e MYSQL_ROOT_PASSWORD=supersecret \ + -v /var/lib/mysql \ + mariadb:10.1 + +docker run --name pdns \ + --link pdns-mysql:mysql \ + -d \ + -p 53:53 \ + -p 53:53/udp -p 8080:8080 \ + -e MYSQL_USER=root \ + -e MYSQL_PASS=supersecret \ + -e MYSQL_PORT=3306 \ + psitrax/powerdns \ + --webserver=yes \ + --api=yes \ + --api-key=password \ + --webserver-port=8080 \ + --webserver-loglevel=detailed \ + --loglevel=10 \ + --log-dns-queries=yes \ + --master=yes \ + --disable-syslog \ + --webserver-address=0.0.0.0 \ + --webserver-allow-from=0.0.0.0/0 + + +docker exec -it pdns pdnsutil create-zone example.com diff --git a/testdata/my-custom-solver/config.json b/testdata/my-custom-solver/config.json index 0967ef4..8a253f7 100644 --- a/testdata/my-custom-solver/config.json +++ b/testdata/my-custom-solver/config.json @@ -1 +1,4 @@ -{} +{ + "server" : "http://localhost:8080", + "apikey" : "password" +}