mirror of
https://github.com/cert-manager/webhook-example.git
synced 2025-07-01 22:35:49 +02:00
Updating webhook from source repo.
This commit is contained in:
parent
39b8f8d26a
commit
cd7a52453f
3 changed files with 212 additions and 33 deletions
15
go.mod
15
go.mod
|
@ -8,10 +8,13 @@ replace github.com/cert-manager/cert-manager => github.com/cert-manager/cert-man
|
|||
|
||||
require (
|
||||
github.com/cert-manager/cert-manager v1.11.0
|
||||
github.com/dnsimple/dnsimple-go v1.2.0
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.2
|
||||
k8s.io/apiextensions-apiserver v0.26.0
|
||||
k8s.io/apimachinery v0.26.0
|
||||
k8s.io/client-go v0.26.0
|
||||
k8s.io/klog v0.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -40,6 +43,7 @@ require (
|
|||
github.com/google/cel-go v0.12.5 // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
|
@ -80,12 +84,12 @@ require (
|
|||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/oauth2 v0.4.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/term v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
@ -97,7 +101,6 @@ require (
|
|||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.26.0 // indirect
|
||||
k8s.io/apimachinery v0.26.0 // indirect
|
||||
k8s.io/apiserver v0.26.0 // indirect
|
||||
k8s.io/component-base v0.26.0 // indirect
|
||||
k8s.io/klog/v2 v2.80.1 // indirect
|
||||
|
|
16
go.sum
16
go.sum
|
@ -85,6 +85,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
|
@ -184,11 +186,14 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
@ -331,6 +336,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
|
@ -466,6 +472,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -535,10 +543,14 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -549,6 +561,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -743,6 +757,8 @@ k8s.io/client-go v0.26.0 h1:lT1D3OfO+wIi9UFolCrifbjUUgu7CpLca0AD8ghRLI8=
|
|||
k8s.io/client-go v0.26.0/go.mod h1:I2Sh57A79EQsDmn7F7ASpmru1cceh3ocVT9KlX2jEZg=
|
||||
k8s.io/component-base v0.26.0 h1:0IkChOCohtDHttmKuz+EP3j3+qKmV55rM9gIFTXA7Vs=
|
||||
k8s.io/component-base v0.26.0/go.mod h1:lqHwlfV1/haa14F/Z5Zizk5QmzaVf23nQzCwVOQpfC8=
|
||||
k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c=
|
||||
k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kms v0.26.0 h1:5+GOQLvUajSd0z5ODF52RzB2rHo1HJUSYsVC3Ri3VgI=
|
||||
|
|
214
main.go
214
main.go
|
@ -1,15 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/klog"
|
||||
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/dnsimple/dnsimple-go/dnsimple"
|
||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1"
|
||||
"github.com/cert-manager/cert-manager/pkg/acme/webhook/cmd"
|
||||
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var GroupName = os.Getenv("GROUP_NAME")
|
||||
|
@ -25,25 +34,25 @@ func main() {
|
|||
// webhook, where the Name() method will be used to disambiguate between
|
||||
// the different implementations.
|
||||
cmd.RunWebhookServer(GroupName,
|
||||
&customDNSProviderSolver{},
|
||||
&dnsimpleDNSProviderSolver{},
|
||||
)
|
||||
}
|
||||
|
||||
// customDNSProviderSolver implements the provider-specific logic needed to
|
||||
// dnsimpleDNSProviderSolver implements the provider-specific logic needed to
|
||||
// 'present' an ACME challenge TXT record for your own DNS provider.
|
||||
// To do so, it must implement the `github.com/cert-manager/cert-manager/pkg/acme/webhook.Solver`
|
||||
// interface.
|
||||
type customDNSProviderSolver struct {
|
||||
type dnsimpleDNSProviderSolver struct {
|
||||
// If a Kubernetes 'clientset' is needed, you must:
|
||||
// 1. uncomment the additional `client` field in this structure below
|
||||
// 2. uncomment the "k8s.io/client-go/kubernetes" import at the top of the file
|
||||
// 3. uncomment the relevant code in the Initialize method below
|
||||
// 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
|
||||
client *kubernetes.Clientset
|
||||
}
|
||||
|
||||
// customDNSProviderConfig is a structure that is used to decode into when
|
||||
// dnsimpleDNSProviderConfig is a structure that is used to decode into when
|
||||
// solving a DNS01 challenge.
|
||||
// This information is provided by cert-manager, and may be a reference to
|
||||
// additional configuration that's needed to solve the challenge for this
|
||||
|
@ -57,7 +66,7 @@ type customDNSProviderSolver struct {
|
|||
// You should not include sensitive information here. If credentials need to
|
||||
// be used by your provider here, you should reference a Kubernetes Secret
|
||||
// resource and fetch these credentials using a Kubernetes clientset.
|
||||
type customDNSProviderConfig struct {
|
||||
type dnsimpleDNSProviderConfig struct {
|
||||
// Change the two fields below according to the format of the configuration
|
||||
// to be decoded.
|
||||
// These fields will be set by users in the
|
||||
|
@ -65,6 +74,7 @@ type customDNSProviderConfig struct {
|
|||
|
||||
//Email string `json:"email"`
|
||||
//APIKeySecretRef v1alpha1.SecretKeySelector `json:"apiKeySecretRef"`
|
||||
TokenSecretRef cmmeta.SecretKeySelector `json:"tokenSecretRef"`
|
||||
}
|
||||
|
||||
// Name is used as the name for this DNS solver when referencing it on the ACME
|
||||
|
@ -73,8 +83,105 @@ type customDNSProviderConfig struct {
|
|||
// solvers configured with the same Name() **so long as they do not co-exist
|
||||
// within a single webhook deployment**.
|
||||
// For example, `cloudflare` may be used as the name of a solver.
|
||||
func (c *customDNSProviderSolver) Name() string {
|
||||
return "my-custom-solver"
|
||||
func (c *dnsimpleDNSProviderSolver) Name() string {
|
||||
return "dnsimple"
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) getClient(cfg *dnsimpleDNSProviderConfig, namespace string) (*dnsimple.Client, error) {
|
||||
secretName := cfg.TokenSecretRef.LocalObjectReference.Name
|
||||
klog.V(6).Infof("Try to load secret `%s` with key `%s`", secretName, cfg.TokenSecretRef.Key)
|
||||
sec, err := c.client.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get secret `%s`; %v", secretName, err)
|
||||
}
|
||||
|
||||
secBytes, ok := sec.Data[cfg.TokenSecretRef.Key]
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Key %q not found in secret \"%s/%s\"", cfg.TokenSecretRef.Key, cfg.TokenSecretRef.LocalObjectReference.Name, namespace)
|
||||
}
|
||||
|
||||
apiKey := string(secBytes)
|
||||
|
||||
tc := dnsimple.StaticTokenHTTPClient(context.Background(), apiKey)
|
||||
|
||||
// new client
|
||||
client := dnsimple.NewClient(tc)
|
||||
client.SetUserAgent("cert-manager-webhook-dnsimple")
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) getDomainAndEntry(ch *v1alpha1.ChallengeRequest) (string, string) {
|
||||
// Both ch.ResolvedZone and ch.ResolvedFQDN end with a dot: '.'
|
||||
entry := strings.TrimSuffix(ch.ResolvedFQDN, ch.ResolvedZone)
|
||||
entry = strings.TrimSuffix(entry, ".")
|
||||
domain := strings.TrimSuffix(ch.ResolvedZone, ".")
|
||||
return entry, domain
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) getExistingRecord(cfg *dnsimpleDNSProviderConfig, client *dnsimple.Client, accountID string, zoneName string, entry string, key string) (*dnsimple.ZoneRecord, error) {
|
||||
zone, err := client.Zones.GetZone(context.Background(), accountID, zoneName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get zone: %s", err)
|
||||
}
|
||||
|
||||
// Look for existing TXT records.
|
||||
records, err := client.Zones.ListRecords(context.Background(), accountID, zone.Data.Name, &dnsimple.ZoneRecordListOptions{Type: dnsimple.String("TXT"), Name: dnsimple.String(entry)})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get resource records: %s", err)
|
||||
}
|
||||
|
||||
for _, record := range records.Data {
|
||||
if record.Content == key {
|
||||
return &record, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) updateRecord(cfg *dnsimpleDNSProviderConfig, client *dnsimple.Client, accountID string, record *dnsimple.ZoneRecord, key string) (*dnsimple.ZoneRecord, error) {
|
||||
attributes := dnsimple.ZoneRecordAttributes{Content: key}
|
||||
updatedRecord, err := client.Zones.UpdateRecord(context.Background(), accountID, record.ZoneID, record.ID, attributes)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to update record: %s", err)
|
||||
}
|
||||
|
||||
return updatedRecord.Data, nil
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) createRecord(cfg *dnsimpleDNSProviderConfig, client *dnsimple.Client, accountID string, entry *string, zoneName string, key string) (*dnsimple.ZoneRecord, error) {
|
||||
attributes := dnsimple.ZoneRecordAttributes{Name: entry, Type: "TXT", Content: key, TTL: 60}
|
||||
createdRecord, err := client.Zones.CreateRecord(context.Background(), accountID, zoneName, attributes)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create record: %s", err)
|
||||
}
|
||||
|
||||
return createdRecord.Data, nil
|
||||
}
|
||||
|
||||
func (c *dnsimpleDNSProviderSolver) deleteRecord(cfg *dnsimpleDNSProviderConfig, client *dnsimple.Client, accountID string, zoneName string, record *dnsimple.ZoneRecord) (*dnsimple.ZoneRecord, error) {
|
||||
createdRecord, err := client.Zones.DeleteRecord(context.Background(), accountID, zoneName, record.ID)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to delete record: %s", err)
|
||||
}
|
||||
|
||||
return createdRecord.Data, nil
|
||||
}
|
||||
|
||||
func Whoami(client *dnsimple.Client) (string, error) {
|
||||
whoamiResponse, err := client.Identity.Whoami(context.Background())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return strconv.FormatInt(whoamiResponse.Data.Account.ID, 10), nil
|
||||
}
|
||||
|
||||
// Present is responsible for actually presenting the DNS record with the
|
||||
|
@ -82,16 +189,46 @@ func (c *customDNSProviderSolver) Name() string {
|
|||
// This method should tolerate being called multiple times with the same value.
|
||||
// cert-manager itself will later perform a self check to ensure that the
|
||||
// solver has correctly configured the DNS provider.
|
||||
func (c *customDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
|
||||
func (c *dnsimpleDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
|
||||
cfg, err := loadConfig(ch.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: do something more useful with the decoded configuration
|
||||
fmt.Printf("Decoded configuration %v", cfg)
|
||||
client, err := c.getClient(&cfg, ch.ResourceNamespace)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get client: %s", err)
|
||||
}
|
||||
|
||||
accountID, err := Whoami(client)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch account ID: %s", err)
|
||||
}
|
||||
|
||||
entry, domain := c.getDomainAndEntry(ch)
|
||||
klog.V(6).Infof("present for entry=%s, domain=%s", entry, domain)
|
||||
|
||||
existingRecord, err := c.getExistingRecord(&cfg, client, accountID, domain, entry, ch.Key)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find txt records: %s", err)
|
||||
}
|
||||
|
||||
if existingRecord != nil {
|
||||
_, err = c.updateRecord(&cfg, client, accountID, existingRecord, ch.Key)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update record: %s", err)
|
||||
}
|
||||
} else {
|
||||
_, err = c.createRecord(&cfg, client, accountID, &entry, domain, ch.Key)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create record: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add code that sets a record in the DNS provider's console
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -101,8 +238,36 @@ func (c *customDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
|
|||
// value provided on the ChallengeRequest should be cleaned up.
|
||||
// This is in order to facilitate multiple DNS validations for the same domain
|
||||
// concurrently.
|
||||
func (c *customDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
||||
// TODO: add code that deletes a record from the DNS provider's console
|
||||
func (c *dnsimpleDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
||||
cfg, err := loadConfig(ch.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := c.getClient(&cfg, ch.ResourceNamespace)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get client: %s", err)
|
||||
}
|
||||
|
||||
accountID, err := Whoami(client)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch account ID: %s", err)
|
||||
}
|
||||
|
||||
entry, domain := c.getDomainAndEntry(ch)
|
||||
klog.V(6).Infof("present for entry=%s, domain=%s", entry, domain)
|
||||
|
||||
existingRecord, err := c.getExistingRecord(&cfg, client, accountID, domain, entry, ch.Key)
|
||||
|
||||
if existingRecord != nil {
|
||||
_, err = c.deleteRecord(&cfg, client, accountID, domain, existingRecord)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to delete record: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -115,25 +280,20 @@ func (c *customDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error {
|
|||
// provider accounts.
|
||||
// The stopCh can be used to handle early termination of the webhook, in cases
|
||||
// where a SIGTERM or similar signal is sent to the webhook process.
|
||||
func (c *customDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
|
||||
///// UNCOMMENT THE BELOW CODE TO MAKE A KUBERNETES CLIENTSET AVAILABLE TO
|
||||
///// YOUR CUSTOM DNS PROVIDER
|
||||
func (c *dnsimpleDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error {
|
||||
cl, err := kubernetes.NewForConfig(kubeClientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//cl, err := kubernetes.NewForConfig(kubeClientConfig)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
//c.client = cl
|
||||
|
||||
///// END OF CODE TO MAKE KUBERNETES CLIENTSET AVAILABLE
|
||||
c.client = cl
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadConfig is a small helper function that decodes JSON configuration into
|
||||
// the typed config struct.
|
||||
func loadConfig(cfgJSON *extapi.JSON) (customDNSProviderConfig, error) {
|
||||
cfg := customDNSProviderConfig{}
|
||||
func loadConfig(cfgJSON *extapi.JSON) (dnsimpleDNSProviderConfig, error) {
|
||||
cfg := dnsimpleDNSProviderConfig{}
|
||||
// handle the 'base case' where no configuration has been provided
|
||||
if cfgJSON == nil {
|
||||
return cfg, nil
|
||||
|
|
Loading…
Reference in a new issue