From 439e7989b0f698af6a9c2f3a104075d218d8bc80 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 25 Mar 2024 17:40:38 +0200 Subject: [PATCH] Added mods --- deploy/sthome-webhook/templates/_helpers.tpl | 6 -- deploy/sthome-webhook/values.yaml | 4 +- sthome/config.go | 65 +++++++++++++++++++- sthome/solver_local.go | 39 ++++++++++-- sthome/utils.go | 29 +++++++++ 5 files changed, 128 insertions(+), 15 deletions(-) diff --git a/deploy/sthome-webhook/templates/_helpers.tpl b/deploy/sthome-webhook/templates/_helpers.tpl index d889995..3e862a5 100644 --- a/deploy/sthome-webhook/templates/_helpers.tpl +++ b/deploy/sthome-webhook/templates/_helpers.tpl @@ -47,9 +47,3 @@ Create chart name and version as used by the chart label. {{ printf "%s-webhook-tls" (include "sthome-webhook.fullname" .) }} {{- end -}} -{{/* -Create base64 imagePullSecret using username and password. -*/}} -{{- define "imagePullSecret" }} -{{- printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }} -{{- end }} \ No newline at end of file diff --git a/deploy/sthome-webhook/values.yaml b/deploy/sthome-webhook/values.yaml index b7d6369..e3dd578 100644 --- a/deploy/sthome-webhook/values.yaml +++ b/deploy/sthome-webhook/values.yaml @@ -1,6 +1,6 @@ # The GroupName here is used to identify your company or business unit that # created this webhook. -# For sthome, this may be "webhook.acme.cert-manager.io". +# For sthome, this may be "acme.sthome.net". # This name will need to be referenced in each Issuer's `webhook` stanza to # inform cert-manager of where to send ChallengePayload resources in order to # solve the DNS01 challenge. @@ -16,7 +16,7 @@ image: repository: stuurmcp/cert-manager-webhook-sthome tag: 0.0.1 #pullPolicy should be IfNotPresent. Set to Always for testing purposes - pullPolicy: Always + pullPolicy: IfNotPresent imageCredentials: name: docker-registry-credentials diff --git a/sthome/config.go b/sthome/config.go index 79643b7..66bb1be 100644 --- a/sthome/config.go +++ b/sthome/config.go @@ -1,6 +1,8 @@ package sthome import ( + "strings" + v1 "k8s.io/api/core/v1" ) @@ -24,6 +26,67 @@ type localDNSProviderConfig struct { // These fields will be set by users in the // `issuer.spec.acme.dns01.providers.webhook.config` field. - Email string `json:"email"` + Email string `json:"email"` + // APIKeySecretRef contains the reference information for the Kubernetes + // secret which contains the sthome API Key. APIKeySecretRef v1.SecretKeySelector `json:"apiKeySecretRef"` + // Host is the Base URL (e.g. https://dns.example.ca) of the sthome API. + Host string `json:"host"` + + // Scheme supports HTTP AuthSchemes + // https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml + // + // +optional default "" + APIKeyScheme string `json:"apiKeyScheme"` + + // APIKeyHeaderName is the header name where apiKey will be set + // + // +optional default "X-API-Key" + APIKeyHeaderName string `json:"apiKeyHeaderName"` + + // ServerID is the server ID in the sthome API. + // When unset, defaults to "localhost". + ServerID string `json:"serverID"` + + // Headers are additional headers added to requests to the + // sthome API server. + Headers map[string]string `json:"headers"` + + // CABundle is a PEM encoded CA bundle which will be used in + // certificate validation when connecting to the sthome server. + // + // When left blank, the default system store will be used. + // + // +optional + CABundle []byte `json:"caBundle"` + + // TTL is the time-to-live value of the inserted DNS records. + // + // +optional + TTL int `json:"ttl"` + + // Timeout is the timeout value for requests to the sthome API. + // The value is specified in seconds. + // + // +optional + Timeout int `json:"timeout"` + + // AllowedZones is the list of zones that may be edited. If the list is + // empty, all zones are permitted. + AllowedZones []string `json:"allowed-zones"` +} + +// IsAllowedZone checks if the webhook is allowed to edit the given zone, per +// AllowedZones setting. All zones allowed if AllowedZones is empty (the default setting) +func (cfg localDNSProviderConfig) IsAllowedZone(zone string) bool { + if len(cfg.AllowedZones) == 0 { + return true + } + + for _, allowed := range cfg.AllowedZones { + if zone == allowed || strings.HasSuffix(zone, "."+allowed) { + return true + } + } + return false } diff --git a/sthome/solver_local.go b/sthome/solver_local.go index 0481052..56b9c36 100644 --- a/sthome/solver_local.go +++ b/sthome/solver_local.go @@ -5,6 +5,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/klog/v2" "github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" "github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util" @@ -46,9 +47,34 @@ func (loc *LocalDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error return err } + klog.InfoS("Presenting challenge", "dnsName", ch.DNSName, "resolvedZone", ch.ResolvedZone, "resolvedFQDN", ch.ResolvedFQDN) + + /* + provider, cfg, err := loc.init(ch.Config, ch.ResourceNamespace) + if err != nil { + return fmt.Errorf("failed initializing sthome provider: %v", err) + } + */ + if !cfg.IsAllowedZone(ch.ResolvedZone) { + return fmt.Errorf("zone %s may not be edited per config (allowed zones are %v)", ch.ResolvedZone, cfg.AllowedZones) + } + /* + ctx := context.Background() + records, err := loc.getExistingRecords(ctx, provider, ch.ResolvedZone, ch.ResolvedFQDN) + if err != nil { + return fmt.Errorf("failed loading existing records for %s in domain %s: %v", ch.ResolvedFQDN, ch.ResolvedZone, err) + } + + // Add the record, only if it doesn't exist already + content := quote(ch.Key) + if _, ok := findRecord(records, content); !ok { + disabled := false + records = append(records, sthome.Record{Disabled: &disabled, Content: &content}) + } + */ // TODO: do something more useful with the decoded configuration - fmt.Printf("Decoded configuration %v", cfg) - fmt.Printf("presenting record for %s (%s)\n", ch.ResolvedFQDN, domainName) + klog.InfoS("Decoded configuration %v", cfg) + klog.InfoS("presenting record for %s (%s)\n", ch.ResolvedFQDN, domainName) // TODO: add code that sets a record in the DNS provider's console // shell command @@ -71,7 +97,7 @@ func (loc *LocalDNSProviderSolver) 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 (s *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { +func (loc *LocalDNSProviderSolver) CleanUp(ch *v1alpha1.ChallengeRequest) error { // TODO: add code that deletes a record from the DNS provider's console // shell command @@ -96,19 +122,20 @@ func (s *LocalDNSProviderSolver) 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 *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error { +func (loc *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, stopCh <-chan struct{}) error { cl, err := kubernetes.NewForConfig(kubeClientConfig) if err != nil { return fmt.Errorf("failed to get kubernetes client: %w", err) } - c.client = *cl + loc.client = *cl + klog.InfoS("Successfully initialised kubernetes client!") return nil } func extractDomainName(zone string) string { authZone, err := util.FindZoneByFqdn(zone, util.RecursiveNameservers) if err != nil { - fmt.Printf("could not get zone by fqdn %v", err) + klog.Errorf("could not get zone by fqdn %v", err) return zone } return util.UnFqdn(authZone) diff --git a/sthome/utils.go b/sthome/utils.go index ae07a57..7e996bd 100644 --- a/sthome/utils.go +++ b/sthome/utils.go @@ -25,4 +25,33 @@ func loadConfig(cfgJSON *extapi.JSON) (localDNSProviderConfig, error) { return cfg, nil } +/* +// quote quotes the provide value +func quote(value string) string { + return fmt.Sprintf("\"%s\"", value) +} + +// findRRSet searches through te list of rrsets for a matching entry +// based on type and name. +func findRRSet(rrsets []sthome.RRset, rrtype sthome.RRType, name string) *sthome.RRset { + for _, rrset := range rrsets { + if (rrset.Type != nil && *rrset.Type == sthome.RRTypeTXT) && + (rrset.Name != nil && *rrset.Name == name) { + return &rrset + } + } + + return nil +} +// findRecord locates the record entry with the matching content. +func findRecord(records []sthome.Record, content string) (int, bool) { + for indx, record := range records { + if record.Content != nil && *record.Content == content { + return indx, true + } + } + + return -1, false +} +*/ // end of private repo workaround