From bcaa159649972d48af413781bdf4b9c92d8c3085 Mon Sep 17 00:00:00 2001 From: Martin Weindel Date: Tue, 7 May 2024 10:41:02 +0200 Subject: [PATCH 1/3] option --use-dnsrecords for DNS challenges with DNSRecords --- .../templates/clusterrole.yaml | 14 + .../cert-management/templates/deployment.yaml | 102 ++++ charts/cert-management/values.yaml | 34 ++ cmd/cert-controller-manager/main.go | 13 +- go.mod | 78 ++- go.sum | 462 ++++++++++++++++-- pkg/cert/legobridge/certificate.go | 12 +- pkg/cert/legobridge/delegatingprovider.go | 237 +++++++++ pkg/cert/legobridge/dnscontrollerprovider.go | 242 +-------- pkg/cert/legobridge/dnsrecordprovider.go | 166 +++++++ .../issuer/certificate/reconciler.go | 85 +++- pkg/controller/issuer/controller.go | 3 +- pkg/controller/issuer/core/const.go | 2 + test/functional/basics.go | 4 + test/functional/dnsrecords.go | 316 ++++++++++++ ...-extensions.gardener.cloud_dnsrecords.yaml | 282 +++++++++++ test/functional/run.sh | 14 +- 17 files changed, 1767 insertions(+), 299 deletions(-) create mode 100644 pkg/cert/legobridge/delegatingprovider.go create mode 100644 pkg/cert/legobridge/dnsrecordprovider.go create mode 100644 test/functional/dnsrecords.go create mode 100644 test/functional/resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml diff --git a/charts/cert-management/templates/clusterrole.yaml b/charts/cert-management/templates/clusterrole.yaml index 74949ba0..db5afb1a 100644 --- a/charts/cert-management/templates/clusterrole.yaml +++ b/charts/cert-management/templates/clusterrole.yaml @@ -95,6 +95,19 @@ rules: - update - create - watch +{{- if .Values.configuration.useDnsRecords }} +- apiGroups: + - extensions.gardener.cloud + resources: + - dnsrecords + verbs: + - get + - list + - update + - watch + - create + - delete +{{- else }} - apiGroups: - dns.gardener.cloud resources: @@ -106,3 +119,4 @@ rules: - watch - create - delete +{{- end }} diff --git a/charts/cert-management/templates/deployment.yaml b/charts/cert-management/templates/deployment.yaml index 46b33cc2..eb9f1219 100644 --- a/charts/cert-management/templates/deployment.yaml +++ b/charts/cert-management/templates/deployment.yaml @@ -71,15 +71,24 @@ spec: {{- if .Values.configuration.cpuprofile }} - --cpuprofile={{ .Values.configuration.cpuprofile }} {{- end }} + {{- if .Values.configuration.defaultEcdsaPrivateKeySize }} + - --default-ecdsa-private-key-size={{ .Values.configuration.defaultEcdsaPrivateKeySize }} + {{- end }} {{- if .Values.configuration.defaultIssuer }} - --default-issuer={{ .Values.configuration.defaultIssuer }} {{- end }} {{- if .Values.configuration.defaultIssuerDomainRanges }} - --default-issuer-domain-ranges={{ .Values.configuration.defaultIssuerDomainRanges }} {{- end }} + {{- if .Values.configuration.defaultPrivateKeyAlgorithm }} + - --default-private-key-algorithm={{ .Values.configuration.defaultPrivateKeyAlgorithm }} + {{- end }} {{- if .Values.configuration.defaultRequestsPerDayQuota }} - --default-requests-per-day-quota={{ .Values.configuration.defaultRequestsPerDayQuota }} {{- end }} + {{- if .Values.configuration.defaultRsaPrivateKeySize }} + - --default-rsa-private-key-size={{ .Values.configuration.defaultRsaPrivateKeySize }} + {{- end }} {{- if .Values.configuration.defaultPoolResyncPeriod }} - --default.pool.resync-period={{ .Values.configuration.defaultPoolResyncPeriod }} {{- end }} @@ -116,6 +125,9 @@ spec: {{- if .Values.configuration.gracePeriod }} - --grace-period={{ .Values.configuration.gracePeriod }} {{- end }} + {{- if .Values.configuration.httproutesPoolSize }} + - --httproutes.pool.size={{ .Values.configuration.httproutesPoolSize }} + {{- end }} {{- if .Values.configuration.ingressCertCertClass }} - --ingress-cert.cert-class={{ .Values.configuration.ingressCertCertClass }} {{- end }} @@ -158,15 +170,24 @@ spec: {{- if .Values.configuration.issuerCertClass }} - --issuer.cert-class={{ .Values.configuration.issuerCertClass }} {{- end }} + {{- if .Values.configuration.issuerDefaultEcdsaPrivateKeySize }} + - --issuer.default-ecdsa-private-key-size={{ .Values.configuration.issuerDefaultEcdsaPrivateKeySize }} + {{- end }} {{- if .Values.configuration.issuerDefaultIssuer }} - --issuer.default-issuer={{ .Values.configuration.issuerDefaultIssuer }} {{- end }} {{- if .Values.configuration.issuerDefaultIssuerDomainRanges }} - --issuer.default-issuer-domain-ranges={{ .Values.configuration.issuerDefaultIssuerDomainRanges }} {{- end }} + {{- if .Values.configuration.issuerDefaultPrivateKeyAlgorithm }} + - --issuer.default-private-key-algorithm={{ .Values.configuration.issuerDefaultPrivateKeyAlgorithm }} + {{- end }} {{- if .Values.configuration.issuerDefaultRequestsPerDayQuota }} - --issuer.default-requests-per-day-quota={{ .Values.configuration.issuerDefaultRequestsPerDayQuota }} {{- end }} + {{- if .Values.configuration.issuerDefaultRsaPrivateKeySize }} + - --issuer.default-rsa-private-key-size={{ .Values.configuration.issuerDefaultRsaPrivateKeySize }} + {{- end }} {{- if .Values.configuration.issuerDefaultPoolResyncPeriod }} - --issuer.default.pool.resync-period={{ .Values.configuration.issuerDefaultPoolResyncPeriod }} {{- end }} @@ -215,9 +236,75 @@ spec: {{- if .Values.configuration.issuerSecretsPoolSize }} - --issuer.secrets.pool.size={{ .Values.configuration.issuerSecretsPoolSize }} {{- end }} + {{- if .Values.configuration.issuerUseDnsrecords }} + - --issuer.use-dnsrecords={{ .Values.configuration.issuerUseDnsrecords }} + {{- end }} {{- if .Values.configuration.issuersPoolSize }} - --issuers.pool.size={{ .Values.configuration.issuersPoolSize }} {{- end }} + {{- if .Values.configuration.istioGatewaysDnsCertClass }} + - --istio-gateways-dns.cert-class={{ .Values.configuration.istioGatewaysDnsCertClass }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsCertTargetClass }} + - --istio-gateways-dns.cert-target-class={{ .Values.configuration.istioGatewaysDnsCertTargetClass }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsDefaultPoolResyncPeriod }} + - --istio-gateways-dns.default.pool.resync-period={{ .Values.configuration.istioGatewaysDnsDefaultPoolResyncPeriod }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsDefaultPoolSize }} + - --istio-gateways-dns.default.pool.size={{ .Values.configuration.istioGatewaysDnsDefaultPoolSize }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsPoolResyncPeriod }} + - --istio-gateways-dns.pool.resync-period={{ .Values.configuration.istioGatewaysDnsPoolResyncPeriod }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsPoolSize }} + - --istio-gateways-dns.pool.size={{ .Values.configuration.istioGatewaysDnsPoolSize }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsTargetNamePrefix }} + - --istio-gateways-dns.target-name-prefix={{ .Values.configuration.istioGatewaysDnsTargetNamePrefix }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsTargetNamespace }} + - --istio-gateways-dns.target-namespace={{ .Values.configuration.istioGatewaysDnsTargetNamespace }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsTargetsPoolSize }} + - --istio-gateways-dns.targets.pool.size={{ .Values.configuration.istioGatewaysDnsTargetsPoolSize }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsTargetsourcesPoolSize }} + - --istio-gateways-dns.targetsources.pool.size={{ .Values.configuration.istioGatewaysDnsTargetsourcesPoolSize }} + {{- end }} + {{- if .Values.configuration.istioGatewaysDnsVirtualservicesPoolSize }} + - --istio-gateways-dns.virtualservices.pool.size={{ .Values.configuration.istioGatewaysDnsVirtualservicesPoolSize }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsCertClass }} + - --k8s-gateways-dns.cert-class={{ .Values.configuration.k8sGatewaysDnsCertClass }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsCertTargetClass }} + - --k8s-gateways-dns.cert-target-class={{ .Values.configuration.k8sGatewaysDnsCertTargetClass }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsDefaultPoolResyncPeriod }} + - --k8s-gateways-dns.default.pool.resync-period={{ .Values.configuration.k8sGatewaysDnsDefaultPoolResyncPeriod }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsDefaultPoolSize }} + - --k8s-gateways-dns.default.pool.size={{ .Values.configuration.k8sGatewaysDnsDefaultPoolSize }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsHttproutesPoolSize }} + - --k8s-gateways-dns.httproutes.pool.size={{ .Values.configuration.k8sGatewaysDnsHttproutesPoolSize }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsPoolResyncPeriod }} + - --k8s-gateways-dns.pool.resync-period={{ .Values.configuration.k8sGatewaysDnsPoolResyncPeriod }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsPoolSize }} + - --k8s-gateways-dns.pool.size={{ .Values.configuration.k8sGatewaysDnsPoolSize }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsTargetNamePrefix }} + - --k8s-gateways-dns.target-name-prefix={{ .Values.configuration.k8sGatewaysDnsTargetNamePrefix }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsTargetNamespace }} + - --k8s-gateways-dns.target-namespace={{ .Values.configuration.k8sGatewaysDnsTargetNamespace }} + {{- end }} + {{- if .Values.configuration.k8sGatewaysDnsTargetsPoolSize }} + - --k8s-gateways-dns.targets.pool.size={{ .Values.configuration.k8sGatewaysDnsTargetsPoolSize }} + {{- end }} {{- if .Values.configuration.kubeconfig }} - --kubeconfig={{ .Values.configuration.kubeconfig }} {{- end }} @@ -353,9 +440,24 @@ spec: {{- if .Values.configuration.targetsPoolSize }} - --targets.pool.size={{ .Values.configuration.targetsPoolSize }} {{- end }} + {{- if .Values.configuration.targetsourcesPoolSize }} + - --targetsources.pool.size={{ .Values.configuration.targetsourcesPoolSize }} + {{- end }} + {{- if .Values.configuration.useDnsrecords }} + - --use-dnsrecords={{ .Values.configuration.useDnsrecords }} + {{- end }} {{- if .Values.configuration.version }} - --version={{ .Values.configuration.version }} {{- end }} + {{- if .Values.configuration.virtualservicesPoolSize }} + - --virtualservices.pool.size={{ .Values.configuration.virtualservicesPoolSize }} + {{- end }} + {{- if .Values.configuration.watchGatewaysCrdsDefaultPoolSize }} + - --watch-gateways-crds.default.pool.size={{ .Values.configuration.watchGatewaysCrdsDefaultPoolSize }} + {{- end }} + {{- if .Values.configuration.watchGatewaysCrdsPoolSize }} + - --watch-gateways-crds.pool.size={{ .Values.configuration.watchGatewaysCrdsPoolSize }} + {{- end }} ### end generated configuration {{- range $idx, $flag := .Values.additionalConfiguration }} - {{ $flag }} diff --git a/charts/cert-management/values.yaml b/charts/cert-management/values.yaml index b37149d4..46305550 100644 --- a/charts/cert-management/values.yaml +++ b/charts/cert-management/values.yaml @@ -41,9 +41,12 @@ configuration: # config: # controllers: # cpuprofile: + # defaultEcdsaPrivateKeySize: # defaultIssuer: # defaultIssuerDomainRanges: + # defaultPrivateKeyAlgorithm: # defaultRequestsPerDayQuota: + # defaultRsaPrivateKeySize: # defaultPoolResyncPeriod: # defaultPoolSize: # disableNamespaceRestriction: @@ -56,6 +59,7 @@ configuration: # dnsMigrationIds: # forceCrdUpdate: # gracePeriod: + # httproutesPoolSize: # ingressCertCertClass: # ingressCertCertTargetClass: # ingressCertDefaultPoolResyncPeriod: @@ -70,9 +74,12 @@ configuration: # issuerAllowTargetIssuers: # issuerCascadeDelete: # issuerCertClass: + # issuerDefaultEcdsaPrivateKeySize: # issuerDefaultIssuer: # issuerDefaultIssuerDomainRanges: + # issuerDefaultPrivateKeyAlgorithm: # issuerDefaultRequestsPerDayQuota: + # issuerDefaultRsaPrivateKeySize: # issuerDefaultPoolResyncPeriod: # issuerDefaultPoolSize: # issuerDnsClass: @@ -89,7 +96,29 @@ configuration: # issuerRenewalWindow: # issuerRevocationsPoolSize: # issuerSecretsPoolSize: + # issuerUseDnsrecords: # issuersPoolSize: + # istioGatewaysDnsCertClass: + # istioGatewaysDnsCertTargetClass: + # istioGatewaysDnsDefaultPoolResyncPeriod: + # istioGatewaysDnsDefaultPoolSize: + # istioGatewaysDnsPoolResyncPeriod: + # istioGatewaysDnsPoolSize: + # istioGatewaysDnsTargetNamePrefix: + # istioGatewaysDnsTargetNamespace: + # istioGatewaysDnsTargetsPoolSize: + # istioGatewaysDnsTargetsourcesPoolSize: + # istioGatewaysDnsVirtualservicesPoolSize: + # k8sGatewaysDnsCertClass: + # k8sGatewaysDnsCertTargetClass: + # k8sGatewaysDnsDefaultPoolResyncPeriod: + # k8sGatewaysDnsDefaultPoolSize: + # k8sGatewaysDnsHttproutesPoolSize: + # k8sGatewaysDnsPoolResyncPeriod: + # k8sGatewaysDnsPoolSize: + # k8sGatewaysDnsTargetNamePrefix: + # k8sGatewaysDnsTargetNamespace: + # k8sGatewaysDnsTargetsPoolSize: # kubeconfig: # kubeconfigDisableDeployCrds: # kubeconfigId: @@ -135,6 +164,11 @@ configuration: # targetId: # targetMigrationIds: # targetsPoolSize: + # targetsourcesPoolSize: + # useDnsrecords: # version: + # virtualservicesPoolSize: + # watchGatewaysCrdsDefaultPoolSize: + # watchGatewaysCrdsPoolSize: additionalConfiguration: [] diff --git a/cmd/cert-controller-manager/main.go b/cmd/cert-controller-manager/main.go index 47a87abd..66b8ecec 100644 --- a/cmd/cert-controller-manager/main.go +++ b/cmd/cert-controller-manager/main.go @@ -10,7 +10,7 @@ import ( "fmt" "os" - "github.com/gardener/controller-manager-library/pkg/utils" + extensionsv1alpha "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" istionetworkingv1 "istio.io/client-go/pkg/apis/networking/v1" istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" @@ -26,6 +26,7 @@ import ( "github.com/gardener/controller-manager-library/pkg/controllermanager/cluster" "github.com/gardener/controller-manager-library/pkg/controllermanager/controller/mappings" "github.com/gardener/controller-manager-library/pkg/resources" + "github.com/gardener/controller-manager-library/pkg/utils" dnsapi "github.com/gardener/external-dns-management/pkg/apis/dns/v1alpha1" @@ -57,7 +58,7 @@ func init() { cluster.Configure( ctrl.DNSCluster, "dns", - "cluster for writing challenge DNS entries", + "cluster for writing challenge DNSEntries or DNSRecords", ).MustRegister() mappings.ForControllerGroup(ctrl.ControllerGroupCert). @@ -71,6 +72,7 @@ func init() { utils.Must(resources.Register(corev1.SchemeBuilder)) utils.Must(resources.Register(dnsapi.SchemeBuilder)) utils.Must(resources.Register(v1alpha1.SchemeBuilder)) + utils.Must(resources.Register(extensionsv1alpha.SchemeBuilder)) utils.Must(resources.Register(coordinationv1.SchemeBuilder)) utils.Must(resources.Register(istionetworkingv1alpha3.SchemeBuilder)) utils.Must(resources.Register(istionetworkingv1beta1.SchemeBuilder)) @@ -80,11 +82,6 @@ func init() { utils.Must(resources.Register(gatewayapisv1.SchemeBuilder)) } -func migrateExtensionsIngress(c controllermanager.Configuration) controllermanager.Configuration { - return c.GlobalGroupKindMigrations(resources.NewGroupKind("extensions", "Ingress"), - resources.NewGroupKind("networking.k8s.io", "Ingress")) -} - func main() { if len(os.Args) == 2 && os.Args[1] == "version" { fmt.Println(version) @@ -92,5 +89,5 @@ func main() { } // set LEGO_DISABLE_CNAME_SUPPORT=true as we have our own logic for FollowCNAME os.Setenv("LEGO_DISABLE_CNAME_SUPPORT", "true") - controllermanager.Start("cert-controller-manager", "Certificate controller manager", "nothing", migrateExtensionsIngress) + controllermanager.Start("cert-controller-manager", "Certificate controller manager", "nothing") } diff --git a/go.mod b/go.mod index 7df181b5..cbffecad 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/gardener/cert-management -go 1.22 +go 1.22.0 + +toolchain go1.22.2 require ( github.com/Masterminds/semver/v3 v3.2.1 @@ -8,24 +10,26 @@ require ( github.com/cert-manager/cert-manager v1.11.0 github.com/gardener/controller-manager-library v0.2.1-0.20240319084608-80ef8dceee73 github.com/gardener/external-dns-management v0.18.4 + github.com/gardener/gardener v1.94.0 github.com/go-acme/lego/v4 v4.15.0 github.com/miekg/dns v1.1.58 github.com/onsi/ginkgo/v2 v2.17.3 github.com/onsi/gomega v1.33.1 github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 - github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_golang v1.18.0 golang.org/x/crypto v0.22.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 golang.org/x/net v0.24.0 istio.io/api v1.22.0 istio.io/client-go v1.22.0 - k8s.io/api v0.29.0 - k8s.io/apiextensions-apiserver v0.28.3 - k8s.io/apimachinery v0.29.0 - k8s.io/client-go v0.29.0 - k8s.io/code-generator v0.28.3 + k8s.io/api v0.29.4 + k8s.io/apiextensions-apiserver v0.29.4 + k8s.io/apimachinery v0.29.4 + k8s.io/client-go v0.29.4 + k8s.io/code-generator v0.29.4 k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 - k8s.io/utils v0.0.0-20240102154912-e7106e64919e + k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 + sigs.k8s.io/controller-runtime v0.17.3 sigs.k8s.io/gateway-api v1.0.0 sigs.k8s.io/kind v0.20.0 software.sslmate.com/src/go-pkcs12 v0.4.0 @@ -34,25 +38,35 @@ require ( require ( github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/BurntSushi/toml v1.3.2 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.7.0 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/evanphx/json-patch/v5 v5.8.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/fluent/fluent-operator/v2 v2.8.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gardener/etcd-druid v0.22.0 // indirect + github.com/gardener/hvpa-controller/api v0.15.0 // indirect + github.com/gardener/machine-controller-manager v0.53.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/go-logr/logr v1.4.1 // indirect + github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/jsonpointer v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.2 // indirect + github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -61,48 +75,68 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ironcore-dev/vgopath v0.1.3 // indirect + github.com/ironcore-dev/vgopath v0.1.4 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.73.2 // indirect + github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.20.0 // indirect - google.golang.org/appengine v1.6.8 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/component-base v0.28.3 // indirect + helm.sh/helm/v3 v3.14.4 // indirect + k8s.io/autoscaler/vertical-pod-autoscaler v1.1.1 // indirect + k8s.io/component-base v0.29.4 // indirect k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 // indirect k8s.io/klog v1.0.0 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-aggregator v0.26.4 // indirect - sigs.k8s.io/controller-tools v0.13.0 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-aggregator v0.29.4 // indirect + k8s.io/kubelet v0.29.4 // indirect + k8s.io/metrics v0.29.4 // indirect + sigs.k8s.io/controller-tools v0.14.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 5a528e6c..8a186ad5 100644 --- a/go.sum +++ b/go.sum @@ -1,63 +1,148 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 h1:+XfOU14S4bGuwyvCijJwhhBIjYN+YXS18jrCY2EzJaY= github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cert-manager/cert-manager v1.11.0 h1:sChJmoj9hhWuFkQMDYHnLHgYA/sSVil+hY+A1lnD3jY= github.com/cert-manager/cert-manager v1.11.0/go.mod h1:JCy2jvRi3Kp+qnRfw8TVYkOocj1thw/aDWFEHPpv4Q4= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= -github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= +github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fluent/fluent-operator/v2 v2.8.0 h1:G6TB1Fq6wx+HflXmv2mc7bhj2MiDoT9OfAeq/XkPCgI= +github.com/fluent/fluent-operator/v2 v2.8.0/go.mod h1:nGKS5Iryq98Jqt+Ixc8YSMmOzM/yNxD8Xwtt76DhmTg= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gardener/controller-manager-library v0.2.1-0.20240319084608-80ef8dceee73 h1:eMPhfzddShJATyxZ+beHzokNvpwIQcrwcNh92TUqz9k= github.com/gardener/controller-manager-library v0.2.1-0.20240319084608-80ef8dceee73/go.mod h1:r8N9I+opiPYEG2cm3A3n2RoEWFUQ/23AspSLPY8S0iQ= +github.com/gardener/etcd-druid v0.22.0 h1:DVe+Zjrb93r9vI1uUiCTMHBffIUoMAKhNzFZNC6hsQ8= +github.com/gardener/etcd-druid v0.22.0/go.mod h1:FROhfVKyWBo4krlPe3R6FIhJRmOmijEWBdEeUP0CJjE= github.com/gardener/external-dns-management v0.18.4 h1:v8TA3XgkU2THdyJfqeJKr/60bPe5znce15X5lz3pjAU= github.com/gardener/external-dns-management v0.18.4/go.mod h1:7aFu4BUkFEM1Il8GbWhHczA2UiGwNI4vjcTaTMthwwE= +github.com/gardener/gardener v1.94.0 h1:mWBzXd29trsCHWTK/uWiJ3kedMvJ7bcxuj2hCZh3+9I= +github.com/gardener/gardener v1.94.0/go.mod h1:DafV6m+tMfAbdye2EeRShvOtRxxixCRd9Y5zy0mPahc= +github.com/gardener/hvpa-controller/api v0.15.0 h1:igsalL5Z6kFMn1+Kv1Eq0cRjYW+4oBA1aEY/yDO2QtI= +github.com/gardener/hvpa-controller/api v0.15.0/go.mod h1:fqb4wNrQLESDKpm7ppXyCM2Gvx96wRlLL35aH0ge07U= +github.com/gardener/machine-controller-manager v0.53.0 h1:g2O0F7nEYZ9LjyPY6Gew8+q0n+rU88deexNq5k8CKks= +github.com/gardener/machine-controller-manager v0.53.0/go.mod h1:XWXHaTy32TU0qmLjWqOgtw8NncdB0HfFzXhUUrcpr7Y= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-acme/lego/v4 v4.15.0 h1:A7MHEU3b+TDFqhC/HmzMJnzPbyeaYvMZQBbqgvbThhU= github.com/go-acme/lego/v4 v4.15.0/go.mod h1:eeGhjW4zWT7Ccqa3sY7ayEqFLCAICx+mXgkMHKIkLxg= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= +github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= @@ -65,18 +150,40 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/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.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -84,34 +191,74 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.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= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ironcore-dev/vgopath v0.1.3 h1:/g3QJ29VrUkYEy52kcUhtvQ3mxfbMIlI1uvEbmt6S4E= -github.com/ironcore-dev/vgopath v0.1.3/go.mod h1:edfsCmU2M4r2N+t4RebSluq//tF3vzogyiDDhcf7MXs= +github.com/ironcore-dev/vgopath v0.1.4 h1:hBMuv7+wnZp5JHkVfdg4mtP8hsIGvuv42+l+F2wmQxk= +github.com/ironcore-dev/vgopath v0.1.4/go.mod h1:PTGnX8xW/QDytFR7oU4kcXr1RPDLCgAJ0ZUa5Rp8vyI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 h1:nHHjmvjitIiyPlUHk/ofpgvBcNcawJLtf4PYHORLjAA= +github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0/go.mod h1:YBCo4DoEeDndqvAn6eeu0vWM7QdXmHEeI9cFWplmBys= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -124,56 +271,96 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= 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= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU= github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 h1:y9azNmMzvkNBPyczpNRwaV4bm0U6e7Oyrj7gi2/SNFI= github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.73.2 h1:GwlGJPK6vf1UIohpc72KJVkKYlzki1UgE3xC4bWbf20= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.73.2/go.mod h1:yJ3CawR/A5qEYFEeCOUVYLTwYxmacfHQhJS+b/2QiaM= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -181,19 +368,62 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -201,19 +431,43 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +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= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -221,8 +475,21 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -232,6 +499,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -240,26 +508,53 @@ golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -270,70 +565,139 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.14.4 h1:6FSpEfqyDalHq3kUr4gOMThhgY55kXUEjdQoyODYnrM= +helm.sh/helm/v3 v3.14.4/go.mod h1:Tje7LL4gprZpuBNTbG34d1Xn5NmRT3OWfBRwpOSer9I= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= istio.io/api v1.22.0 h1:CdMUHgN/OfQK9ojj6lCjxlJSuUe0vD0ZAvoCcoBfn20= istio.io/api v1.22.0/go.mod h1:S3l8LWqNYS9yT+d4bH+jqzH2lMencPkW7SKM1Cu9EyM= istio.io/client-go v1.22.0 h1:TQ+Y7hqZVQHvaJXF99Q1jBqnVG7gYAHR9IvCK2nlwfE= istio.io/client-go v1.22.0/go.mod h1:1lAPr0DOVBbnRQqLAQKxWbEaxFk6b1CJTm+ypnP7sMo= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= -k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= -k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/code-generator v0.28.3 h1:I847QvdpYx7xKiG2KVQeCSyNF/xU9TowaDAg601mvlw= -k8s.io/code-generator v0.28.3/go.mod h1:A2EAHTRYvCvBrb/MM2zZBNipeCk3f8NtpdNIKawC43M= -k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= -k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= +k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= +k8s.io/api v0.29.4 h1:WEnF/XdxuCxdG3ayHNRR8yH3cI1B/llkWBma6bq4R3w= +k8s.io/api v0.29.4/go.mod h1:DetSv0t4FBTcEpfA84NJV3g9a7+rSzlUHk5ADAYHUv0= +k8s.io/apiextensions-apiserver v0.29.4 h1:M7hbuHU/ckbibR7yPbe6DyNWgTFKNmZDbdZKD8q1Smk= +k8s.io/apiextensions-apiserver v0.29.4/go.mod h1:TTDC9fB+0kHY2rogf5hgBR03KBKCwED+GHUsXGpR7SM= +k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.29.4 h1:RaFdJiDmuKs/8cm1M6Dh1Kvyh59YQFDcFuFTSmXes6Q= +k8s.io/apimachinery v0.29.4/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y= +k8s.io/apiserver v0.29.4 h1:wPwGOO58GQOpRiZu59P5eRoDcB7QtV+QBglkRiXwCiM= +k8s.io/apiserver v0.29.4/go.mod h1:VqTF9t98HVfhKZVRohCPezsdUt9u2g3bHKftxGcXoRo= +k8s.io/autoscaler/vertical-pod-autoscaler v1.1.1 h1:cz1xqf+WccJcvEaDd9sefJVx7bEldJT5RLQWViRgoTI= +k8s.io/autoscaler/vertical-pod-autoscaler v1.1.1/go.mod h1:J2cNKnieE7r4bInjpQDBq93D50aD/CmspSi6xRUfKk4= +k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= +k8s.io/client-go v0.29.4 h1:79ytIedxVfyXV8rpH3jCBW0u+un0fxHDwX5F9K8dPR8= +k8s.io/client-go v0.29.4/go.mod h1:kC1thZQ4zQWYwldsfI088BbK6RkxK+aF5ebV8y9Q4tk= +k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/code-generator v0.29.4 h1:8ESudFNbY5/9BzB8KOEFG2uV9Q0AQxkc4mrQESr30Ks= +k8s.io/code-generator v0.29.4/go.mod h1:7TYnI0dYItL2cKuhhgPSuF3WED9uMdELgbVXFfn/joE= +k8s.io/component-base v0.29.4 h1:xeKzuuHI/1tjleu5jycDAcYbhAxeGHCQBZUY2eRIkOo= +k8s.io/component-base v0.29.4/go.mod h1:pYjt+oEZP9gtmwSikwAJgfSBikqKX2gOqRat0QjmQt0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kube-aggregator v0.26.4 h1:iGljhq5exQkbuc3bnkwUx95RPCBDExg7DkX9XaYhg6w= -k8s.io/kube-aggregator v0.26.4/go.mod h1:eWfg4tU0+l57ebWiS5THOANIJUrKRxudSVDJ+63bqvQ= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-aggregator v0.29.4 h1:yT7vYtwIag4G8HNrktYZ3qz6p6oHKronMAXOw4eQ2WQ= +k8s.io/kube-aggregator v0.29.4/go.mod h1:zBfe4iXXmw5HinNgN0JoAu5rpXdyCUvRfG99+FVOd68= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= -k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-tools v0.13.0 h1:NfrvuZ4bxyolhDBt/rCZhDnx3M2hzlhgo5n3Iv2RykI= -sigs.k8s.io/controller-tools v0.13.0/go.mod h1:5vw3En2NazbejQGCeWKRrE7q4P+CW8/klfVqP8QZkgA= +k8s.io/kubelet v0.29.4 h1:6fTt4sTd5xqTtIhVoS7PkiFUBevQsyu3ZmENVvwY62M= +k8s.io/kubelet v0.29.4/go.mod h1:lAu6Z17pxKwgM+9hsgGkqFjYTOhbc0dnZ6GNnlbjYW0= +k8s.io/metrics v0.29.4 h1:06sZ63/Kt9HEb5GP/1y6xbHDz6XkxnHpu949UdXfoXQ= +k8s.io/metrics v0.29.4/go.mod h1:ZN9peB0nLTqPZuwQna8ZUrPFJQ0i8QNH4pqRJopS+9c= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/controller-runtime v0.17.3 h1:65QmN7r3FWgTxDMz9fvGnO1kbf2nu+acg9p2R9oYYYk= +sigs.k8s.io/controller-runtime v0.17.3/go.mod h1:N0jpP5Lo7lMTF9aL56Z/B2oWBJjey6StQM0jRbKQXtY= +sigs.k8s.io/controller-tools v0.14.0 h1:rnNoCC5wSXlrNoBKKzL70LNJKIQKEzT6lloG6/LF73A= +sigs.k8s.io/controller-tools v0.14.0/go.mod h1:TV7uOtNNnnR72SpzhStvPkoS/U5ir0nMudrkrC4M9Sc= sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/pkg/cert/legobridge/certificate.go b/pkg/cert/legobridge/certificate.go index 91b5e3ee..414722ae 100644 --- a/pkg/cert/legobridge/certificate.go +++ b/pkg/cert/legobridge/certificate.go @@ -84,6 +84,16 @@ type DNSControllerSettings struct { PropagationTimeout time.Duration // FollowCNAME if true checks and follows CNAME records for DNS01 challenge domains. FollowCNAME bool + // DNSRecordSettings are additional fields needed to create a DNSRecord. If set, DNSChallenge will use DNSRecords instead of DNSEntries. + DNSRecordSettings *DNSRecordSettings +} + +// DNSRecordSettings are additional fields needed to create a DNSRecord. +type DNSRecordSettings struct { + // Type is the provider type. + Type string + // SecretRef is a reference to a secret that contains the cloud provider specific credentials. + SecretRef corev1.SecretReference } // ObtainOutput is the result of the certificate obtain request. @@ -328,7 +338,7 @@ func (o *obtainer) ObtainACME(input ObtainInput) error { var provider ProviderWithCount if input.DNSSettings != nil { - provider, err = newDNSControllerProvider(*input.DNSSettings, input.RequestName, + provider, err = newDelegatingProvider(*input.DNSSettings, input.RequestName, input.TargetClass, input.IssuerKey) if err != nil { o.releasePending(input) diff --git a/pkg/cert/legobridge/delegatingprovider.go b/pkg/cert/legobridge/delegatingprovider.go new file mode 100644 index 00000000..7a0b657e --- /dev/null +++ b/pkg/cert/legobridge/delegatingprovider.go @@ -0,0 +1,237 @@ +/* + * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package legobridge + +import ( + "fmt" + "sync/atomic" + "time" + + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/gardener/cert-management/pkg/cert/metrics" + "github.com/gardener/cert-management/pkg/cert/utils" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/challenge/dns01" + + "github.com/gardener/controller-manager-library/pkg/logger" + "github.com/gardener/controller-manager-library/pkg/resources" +) + +// ProviderWithCount is an extended Provider interface. +type ProviderWithCount interface { + challenge.Provider + GetChallengesCount() int + // GetPendingTXTRecordError returns error with details if a TXT record for DNS challenge is not ready. + GetPendingTXTRecordError() error +} + +type internalProvider interface { + present(log logger.LogContext, domain, fqdn string, values []string) (error, bool) + cleanup(log logger.LogContext, domain string) error + + failedDNSResourceReadyMessage(final bool) string + checkDNSResourceReady(domain string, values []string) bool +} + +var serial uint32 + +func newDelegatingProvider( + settings DNSControllerSettings, + certificateName resources.ObjectName, + targetClass string, + issuerKey utils.IssuerKey, +) (ProviderWithCount, error) { + n := atomic.AddUint32(&serial, 1) + var internalPrvdr internalProvider + var err error + if settings.DNSRecordSettings == nil { + internalPrvdr, err = newDNSControllerProvider(settings, targetClass) + } else { + internalPrvdr, err = newDNSRecordProvider(settings) + } + return &delegatingProvider{ + logger: logger.NewContext("DNSChallengeProvider", fmt.Sprintf("dns-challenge-provider: %s-%d", certificateName, n)), + settings: settings, + issuerKey: issuerKey, + initialWait: true, + presenting: map[string][]string{}, + internalProvider: internalPrvdr, + }, err +} + +type delegatingProvider struct { + logger logger.LogContext + settings DNSControllerSettings + issuerKey utils.IssuerKey + count int32 + presenting map[string][]string + initialWait bool + + failedPendingDomain string + failedPendingCheck string + internalProvider internalProvider +} + +var backoff = wait.Backoff{ + Steps: 4, + Duration: 500 * time.Millisecond, + Factor: 2.0, + Jitter: 0.1, + Cap: 2500 * time.Millisecond, +} + +type updateError struct { + msg string +} + +func (e *updateError) Error() string { + return e.msg +} + +func retryOnUpdateError(fn func() error) error { + var lastUpdateErr error + err := wait.ExponentialBackoff(backoff, func() (bool, error) { + err := fn() + _, isUpdateErr := err.(*updateError) + switch { + case err == nil: + return true, nil + case isUpdateErr: + lastUpdateErr = err + return false, nil + default: + return false, err + } + }) + if err == wait.ErrWaitTimeout { + err = lastUpdateErr + } + return err +} + +func (p *delegatingProvider) Present(domain, _, keyAuth string) error { + metrics.AddActiveACMEDNSChallenge(p.issuerKey) + atomic.AddInt32(&p.count, 1) + info := dns01.GetChallengeInfo(domain, keyAuth) + value := info.Value + fqdn := info.FQDN + + if p.settings.FollowCNAME { + var err error + orgfqdn := fqdn + fqdn, err = utils.FollowCNAMEs(fqdn, p.settings.PrecheckNameservers) + if err != nil { + return fmt.Errorf("following CNAME for DNS01 challenge for %s failed: %w", orgfqdn, err) + } + } + + values := p.addPresentingDomainValue(domain, value) + + err, remove := p.internalProvider.present(p.logger, domain, fqdn, values) + if remove { + p.removePresentingDomain(domain) + } + return err +} + +func (p *delegatingProvider) addPresentingDomainValue(domain, value string) []string { + values := append(p.presenting[domain], value) + p.presenting[domain] = values + return values +} + +func (p *delegatingProvider) removePresentingDomain(domain string) bool { + if _, found := p.presenting[domain]; !found { + return false + } + delete(p.presenting, domain) + return true +} + +func (p *delegatingProvider) CleanUp(domain, _, _ string) error { + metrics.RemoveActiveACMEDNSChallenge(p.issuerKey) + + if !p.removePresentingDomain(domain) { + return nil + } + + return p.internalProvider.cleanup(p.logger, domain) +} + +func (p *delegatingProvider) GetChallengesCount() int { + return int(atomic.LoadInt32(&p.count)) +} + +func (p *delegatingProvider) GetPendingTXTRecordError() error { + if p.failedPendingDomain != "" { + return fmt.Errorf("DNS TXT record '_acme-challenge.%s' is not visible on public (or precheck) name servers. Failed check: %s", p.failedPendingDomain, p.failedPendingCheck) + } + return nil +} + +func (p *delegatingProvider) Timeout() (timeout, interval time.Duration) { + waitTimeout := p.settings.PropagationTimeout + if !p.initialWait { + return 10 * time.Second, dns01.DefaultPollingInterval + } + + p.initialWait = false + // The Timeout function is called several times after all domains are "presented". + // On the first call it is checked that no DNS entries are pending anymore. + // Depending on number of domain names and possible parallel other work, + // the dns-controller-manager may need several change batches + // until all entries are ready + + prepareWaitTimeout := 30*time.Second + 5*time.Second*time.Duration(len(p.presenting)) + ok := p.waitFor(p.internalProvider.failedDNSResourceReadyMessage, p.internalProvider.checkDNSResourceReady, prepareWaitTimeout) + if ok { + ok = p.waitFor(func(bool) string { return "DNS record propagation" }, p.isDNSTxtRecordReady, waitTimeout) + } + if ok { + // wait some additional seconds to enlarge probability of record propagation to DNS server use by ACME server + additionalWaitTime := p.settings.AdditionalWait + p.logger.Infof("Waiting additional %d seconds...", int(additionalWaitTime.Seconds())) + time.Sleep(additionalWaitTime) + } + return waitTimeout / 2, dns01.DefaultPollingInterval +} + +func (p *delegatingProvider) waitFor(msgfunc func(bool) string, isReady func(domain string, values []string) bool, timeout time.Duration) bool { + p.failedPendingDomain = "" + p.failedPendingCheck = "" + + waitTime := 5 * time.Second + endTime := time.Now().Add(timeout) + pendingDomain := "" + for time.Now().Before(endTime) { + ready := true + for domain, values := range p.presenting { + if !isReady(domain, values) { + pendingDomain = domain + ready = false + break + } + } + if ready { + return true + } + p.logger.Infof("Waiting %d seconds for %s [%s]...", int(waitTime.Seconds()), msgfunc(false), pendingDomain) + time.Sleep(waitTime) + } + + p.failedPendingDomain = pendingDomain + p.failedPendingCheck = msgfunc(true) + return false +} + +func (p *delegatingProvider) isDNSTxtRecordReady(domain string, values []string) bool { + fqdn := fmt.Sprintf("_acme-challenge.%s.", domain) + found, _ := utils.CheckDNSPropagation(p.settings.PrecheckNameservers, fqdn, values...) + return found +} diff --git a/pkg/cert/legobridge/dnscontrollerprovider.go b/pkg/cert/legobridge/dnscontrollerprovider.go index 2df4c914..e18ef344 100644 --- a/pkg/cert/legobridge/dnscontrollerprovider.go +++ b/pkg/cert/legobridge/dnscontrollerprovider.go @@ -9,17 +9,10 @@ package legobridge import ( "errors" "fmt" - "sync/atomic" "time" - "k8s.io/apimachinery/pkg/util/wait" - - "github.com/gardener/cert-management/pkg/cert/metrics" "github.com/gardener/cert-management/pkg/cert/source" - "github.com/gardener/cert-management/pkg/cert/utils" - - "github.com/go-acme/lego/v4/challenge" - "github.com/go-acme/lego/v4/challenge/dns01" + "k8s.io/utils/ptr" "github.com/gardener/controller-manager-library/pkg/logger" "github.com/gardener/controller-manager-library/pkg/resources" @@ -27,117 +20,33 @@ import ( "github.com/gardener/external-dns-management/pkg/dns" ) -// ProviderWithCount is an extended Provider interface. -type ProviderWithCount interface { - challenge.Provider - GetChallengesCount() int - // GetPendingTXTRecordError returns error with details if a TXT record for DNS challenge is not ready. - GetPendingTXTRecordError() error -} - -var index uint32 - -func newDNSControllerProvider(settings DNSControllerSettings, - certificateName resources.ObjectName, targetClass string, issuerKey utils.IssuerKey) (ProviderWithCount, error) { +func newDNSControllerProvider(settings DNSControllerSettings, targetClass string) (internalProvider, error) { itf, err := settings.Cluster.Resources().GetByExample(&dnsapi.DNSEntry{}) if err != nil { return nil, fmt.Errorf("cannot get DNSEntry resources: %w", err) } - n := atomic.AddUint32(&index, 1) return &dnsControllerProvider{ - logger: logger.NewContext("DNSChallengeProvider", fmt.Sprintf("dns-challenge-provider: %s-%d", certificateName, n)), - settings: settings, - entryResources: itf, - certificateName: certificateName, - targetClass: targetClass, - issuerKey: issuerKey, - ttl: int64(settings.PropagationTimeout.Seconds()), - initialWait: true, - presenting: map[string][]string{}, - entries: map[string]*dnsapi.DNSEntry{}, + settings: settings, + entryResources: itf, + targetClass: targetClass, + entries: map[string]*dnsapi.DNSEntry{}, }, nil } type dnsControllerProvider struct { - logger logger.LogContext - settings DNSControllerSettings - entryResources resources.Interface - certificateName resources.ObjectName - targetClass string - issuerKey utils.IssuerKey - count int32 - ttl int64 - presenting map[string][]string - multiValues bool - initialWait bool - - failedPendingDomain string - failedPendingCheck string - entries map[string]*dnsapi.DNSEntry -} - -var _ challenge.Provider = &dnsControllerProvider{} -var _ challenge.ProviderTimeout = &dnsControllerProvider{} - -var backoff = wait.Backoff{ - Steps: 4, - Duration: 500 * time.Millisecond, - Factor: 2.0, - Jitter: 0.1, - Cap: 2500 * time.Millisecond, -} - -type updateError struct { - msg string -} - -func (e *updateError) Error() string { - return e.msg -} - -func retryOnUpdateError(fn func() error) error { - var lastUpdateErr error - err := wait.ExponentialBackoff(backoff, func() (bool, error) { - err := fn() - _, isUpdateErr := err.(*updateError) - switch { - case err == nil: - return true, nil - case isUpdateErr: - lastUpdateErr = err - return false, nil - default: - return false, err - } - }) - if err == wait.ErrWaitTimeout { - err = lastUpdateErr - } - return err + settings DNSControllerSettings + entryResources resources.Interface + targetClass string + entries map[string]*dnsapi.DNSEntry } -func (p *dnsControllerProvider) Present(domain, _, keyAuth string) error { - metrics.AddActiveACMEDNSChallenge(p.issuerKey) - atomic.AddInt32(&p.count, 1) - info := dns01.GetChallengeInfo(domain, keyAuth) - value := info.Value - fqdn := info.FQDN - - if p.settings.FollowCNAME { - var err error - orgfqdn := fqdn - fqdn, err = utils.FollowCNAMEs(fqdn, p.settings.PrecheckNameservers) - if err != nil { - return fmt.Errorf("following CNAME for DNS01 challenge for %s failed: %w", orgfqdn, err) - } - } - - values := p.addPresentingDomainValue(domain, value) +var _ internalProvider = &dnsControllerProvider{} +func (p *dnsControllerProvider) present(log logger.LogContext, domain, fqdn string, values []string) (error, bool) { setSpec := func(e *dnsapi.DNSEntry) { e.Spec.DNSName = dns.NormalizeHostname(fqdn) e.Spec.OwnerId = p.settings.OwnerID - e.Spec.TTL = &p.ttl + e.Spec.TTL = ptr.To(int64(p.settings.PropagationTimeout.Seconds())) e.Spec.Text = values if p.targetClass != "" { resources.SetAnnotation(e, source.AnnotDNSClass, p.targetClass) @@ -149,19 +58,16 @@ func (p *dnsControllerProvider) Present(domain, _, keyAuth string) error { if len(values) == 1 { setSpec(entry) - p.logger.Infof("presenting DNSEntry %s/%s for certificate resource %s", entry.Namespace, entry.Name, p.certificateName) + log.Infof("presenting DNSEntry %s/%s", entry.Namespace, entry.Name) if p.existsBlockingEntry(entry) { - p.removePresentingDomain(domain) - return fmt.Errorf("already existing DNSEntry %s/%s for certificate resource %s", entry.Namespace, entry.Name, p.certificateName) + return fmt.Errorf("already existing DNSEntry %s/%s", entry.Namespace, entry.Name), true } - _, err := p.entryResources.Create(entry) - if err != nil { - return fmt.Errorf("creating DNSEntry %s/%s failed: %w", entry.Namespace, entry.Name, err) + if _, err := p.entryResources.Create(entry); err != nil { + return fmt.Errorf("creating DNSEntry %s/%s failed: %w", entry.Namespace, entry.Name, err), false } - return nil + return nil, false } - p.multiValues = true err := retryOnUpdateError(func() error { obj, err := p.entryResources.Get_(entry) if err != nil { @@ -169,14 +75,13 @@ func (p *dnsControllerProvider) Present(domain, _, keyAuth string) error { } entry = obj.Data().(*dnsapi.DNSEntry) setSpec(entry) - p.logger.Infof("presenting DNSEntry %s/%s for certificate resource %s with %d values", entry.Namespace, entry.Name, p.certificateName, len(values)) - _, err = p.entryResources.Update(entry) - if err != nil { + log.Infof("presenting DNSEntry %s/%s with %d values", entry.Namespace, entry.Name, len(values)) + if _, err = p.entryResources.Update(entry); err != nil { return &updateError{msg: fmt.Sprintf("updating DNSEntry %s/%s failed: %s", entry.Namespace, entry.Name, err)} } return nil }) - return err + return err, false } func (p *dnsControllerProvider) existsBlockingEntry(entry *dnsapi.DNSEntry) bool { @@ -194,47 +99,15 @@ func (p *dnsControllerProvider) existsBlockingEntry(entry *dnsapi.DNSEntry) bool return keep } -func (p *dnsControllerProvider) addPresentingDomainValue(domain, value string) []string { - values := append(p.presenting[domain], value) - p.presenting[domain] = values - return values -} - -func (p *dnsControllerProvider) removePresentingDomain(domain string) bool { - if _, found := p.presenting[domain]; !found { - return false - } - delete(p.presenting, domain) - return true -} - -func (p *dnsControllerProvider) CleanUp(domain, _, _ string) error { - metrics.RemoveActiveACMEDNSChallenge(p.issuerKey) - - if !p.removePresentingDomain(domain) { - return nil - } - +func (p *dnsControllerProvider) cleanup(log logger.LogContext, domain string) error { entry := p.prepareEntry(domain) - p.logger.Infof("cleanup DNSEntry %s/%s for request %s", entry.Namespace, entry.Name, p.certificateName) - err := p.entryResources.Delete(entry) - if err != nil { + log.Infof("cleanup DNSEntry %s/%s", entry.Namespace, entry.Name) + if err := p.entryResources.Delete(entry); err != nil { return fmt.Errorf("deleting DNSEntry %s/%s failed: %w", entry.Namespace, entry.Name, err) } return nil } -func (p *dnsControllerProvider) GetChallengesCount() int { - return int(atomic.LoadInt32(&p.count)) -} - -func (p *dnsControllerProvider) GetPendingTXTRecordError() error { - if p.failedPendingDomain != "" { - return fmt.Errorf("DNS TXT record '_acme-challenge.%s' is not visible on public (or precheck) name servers. Failed check: %s", p.failedPendingDomain, p.failedPendingCheck) - } - return nil -} - func (p *dnsControllerProvider) prepareEntry(domain string) *dnsapi.DNSEntry { entry := &dnsapi.DNSEntry{} entry.Name = "cert--" + domain @@ -242,7 +115,7 @@ func (p *dnsControllerProvider) prepareEntry(domain string) *dnsapi.DNSEntry { return entry } -func (p *dnsControllerProvider) checkDNSEntryReady(domain string, values []string) bool { +func (p *dnsControllerProvider) checkDNSResourceReady(domain string, _ []string) bool { entry := p.prepareEntry(domain) obj, err := p.entryResources.Get_(entry) if err != nil { @@ -250,10 +123,10 @@ func (p *dnsControllerProvider) checkDNSEntryReady(domain string, values []strin } entry = obj.Data().(*dnsapi.DNSEntry) p.entries[domain] = entry - return entry.Status.State == "Ready" && len(entry.Status.Targets) == len(values) + return entry.Status.State == "Ready" && entry.Status.ObservedGeneration == entry.Generation } -func (p *dnsControllerProvider) failedDNSEntryReadyMessage(final bool) string { +func (p *dnsControllerProvider) failedDNSResourceReadyMessage(final bool) string { if final { var errs []error for key, entry := range p.entries { @@ -274,64 +147,3 @@ func (p *dnsControllerProvider) failedDNSEntryReadyMessage(final bool) string { } return "DNS entry getting ready" } - -func (p *dnsControllerProvider) Timeout() (timeout, interval time.Duration) { - waitTimeout := p.settings.PropagationTimeout - if !p.initialWait { - return 10 * time.Second, dns01.DefaultPollingInterval - } - - p.initialWait = false - // The Timeout function is called several times after all domains are "presented". - // On the first call it is checked that no DNS entries are pending anymore. - // Depending on number of domain names and possible parallel other work, - // the dns-controller-manager may need several change batches - // until all entries are ready - - prepareWaitTimeout := 30*time.Second + 5*time.Second*time.Duration(len(p.presenting)) - ok := p.waitFor(p.failedDNSEntryReadyMessage, p.checkDNSEntryReady, prepareWaitTimeout) - if ok { - ok = p.waitFor(func(bool) string { return "DNS record propagation" }, p.isDNSTxtRecordReady, waitTimeout) - } - if ok { - // wait some additional seconds to enlarge probability of record propagation to DNS server use by ACME server - additionalWaitTime := p.settings.AdditionalWait - p.logger.Infof("Waiting additional %d seconds...", int(additionalWaitTime.Seconds())) - time.Sleep(additionalWaitTime) - } - return waitTimeout / 2, dns01.DefaultPollingInterval -} - -func (p *dnsControllerProvider) waitFor(msgfunc func(bool) string, isReady func(domain string, values []string) bool, timeout time.Duration) bool { - p.failedPendingDomain = "" - p.failedPendingCheck = "" - - waitTime := 5 * time.Second - endTime := time.Now().Add(timeout) - pendingDomain := "" - for time.Now().Before(endTime) { - ready := true - for domain, values := range p.presenting { - if !isReady(domain, values) { - pendingDomain = domain - ready = false - break - } - } - if ready { - return true - } - p.logger.Infof("Waiting %d seconds for %s [%s]...", int(waitTime.Seconds()), msgfunc(false), pendingDomain) - time.Sleep(waitTime) - } - - p.failedPendingDomain = pendingDomain - p.failedPendingCheck = msgfunc(true) - return false -} - -func (p *dnsControllerProvider) isDNSTxtRecordReady(domain string, values []string) bool { - fqdn := fmt.Sprintf("_acme-challenge.%s.", domain) - found, _ := utils.CheckDNSPropagation(p.settings.PrecheckNameservers, fqdn, values...) - return found -} diff --git a/pkg/cert/legobridge/dnsrecordprovider.go b/pkg/cert/legobridge/dnsrecordprovider.go new file mode 100644 index 00000000..466b47ee --- /dev/null +++ b/pkg/cert/legobridge/dnsrecordprovider.go @@ -0,0 +1,166 @@ +/* + * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package legobridge + +import ( + "errors" + "fmt" + "time" + + "github.com/gardener/cert-management/pkg/cert/source" + "github.com/gardener/gardener/pkg/apis/core/v1beta1" + "github.com/gardener/gardener/pkg/utils/gardener" + "k8s.io/utils/ptr" + + "github.com/gardener/controller-manager-library/pkg/logger" + "github.com/gardener/controller-manager-library/pkg/resources" + "github.com/gardener/external-dns-management/pkg/dns" + extensionsv1alpha "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" +) + +func newDNSRecordProvider(settings DNSControllerSettings) (internalProvider, error) { + itf, err := settings.Cluster.Resources().GetByExample(&extensionsv1alpha.DNSRecord{}) + if err != nil { + return nil, fmt.Errorf("cannot get DNSRecord resources: %w", err) + } + if settings.DNSRecordSettings == nil { + return nil, fmt.Errorf("missing DNSRecord specific settings") + } + if settings.DNSRecordSettings.Type == "" { + return nil, fmt.Errorf("missing DNSRecord provider type") + } + if settings.DNSRecordSettings.SecretRef.Name == "" { + return nil, fmt.Errorf("missing DNSRecord secret reference") + } + return &dnsRecordProvider{ + settings: settings, + dnsrecordResources: itf, + entries: map[string]*extensionsv1alpha.DNSRecord{}, + }, nil +} + +type dnsRecordProvider struct { + settings DNSControllerSettings + dnsrecordResources resources.Interface + entries map[string]*extensionsv1alpha.DNSRecord +} + +var _ internalProvider = &dnsRecordProvider{} + +func (p *dnsRecordProvider) present(log logger.LogContext, domain, fqdn string, values []string) (error, bool) { + setSpec := func(e *extensionsv1alpha.DNSRecord) { + e.Spec.Name = dns.NormalizeHostname(fqdn) + e.Spec.TTL = ptr.To(int64(p.settings.PropagationTimeout.Seconds())) + e.Spec.RecordType = extensionsv1alpha.DNSRecordTypeTXT + e.Spec.Type = p.settings.DNSRecordSettings.Type + e.Spec.SecretRef = p.settings.DNSRecordSettings.SecretRef + e.Spec.Values = values + resources.SetAnnotation(e, source.AnnotACMEDNSChallenge, "true") + } + + entry := p.prepareEntry(domain) + + if len(values) == 1 { + setSpec(entry) + log.Infof("presenting DNSRecord %s/%s", entry.Namespace, entry.Name) + if p.existsBlockingEntry(entry) { + return fmt.Errorf("already existing DNSRecord %s/%s", entry.Namespace, entry.Name), true + } + if _, err := p.dnsrecordResources.Create(entry); err != nil { + return fmt.Errorf("creating DNSRecord %s/%s failed: %w", entry.Namespace, entry.Name, err), false + } + return nil, false + } + + err := retryOnUpdateError(func() error { + obj, err := p.dnsrecordResources.Get_(entry) + if err != nil { + return fmt.Errorf("getting DNSRecord %s/%s failed: %w", entry.Namespace, entry.Name, err) + } + entry = obj.Data().(*extensionsv1alpha.DNSRecord) + setSpec(entry) + log.Infof("presenting DNSRecord %s/%s with %d values", entry.Namespace, entry.Name, len(values)) + if _, err = p.dnsrecordResources.Update(entry); err != nil { + return &updateError{msg: fmt.Sprintf("updating DNSRecord %s/%s failed: %s", entry.Namespace, entry.Name, err)} + } + return nil + }) + return err, false +} + +func (p *dnsRecordProvider) existsBlockingEntry(entry *extensionsv1alpha.DNSRecord) bool { + objectName := resources.NewObjectName(entry.Namespace, entry.Name) + obj, err := p.dnsrecordResources.Get_(objectName) + if err != nil { + return false + } + + keep := obj.GetCreationTimestamp().Add(3 * time.Minute).After(time.Now()) + if !keep { + // delete outdated or foreign DNSRecord + _ = p.dnsrecordResources.DeleteByName(objectName) + } + return keep +} + +func (p *dnsRecordProvider) cleanup(log logger.LogContext, domain string) error { + entry := p.prepareEntry(domain) + log.Infof("cleanup DNSRecord %s/%s", entry.Namespace, entry.Name) + if _, err := p.dnsrecordResources.GetInto1(entry); err != nil { + return fmt.Errorf("getting DNSRecord %s/%s failed: %w", entry.Namespace, entry.Name, err) + } + if resources.SetAnnotation(entry, gardener.ConfirmationDeletion, "true") { + if _, err := p.dnsrecordResources.Update(entry); err != nil { + return fmt.Errorf("annotating DNSRecord %s/%s failed: %w", entry.Namespace, entry.Name, err) + } + } + if err := p.dnsrecordResources.Delete(entry); err != nil { + return fmt.Errorf("deleting DNSRecord %s/%s failed: %w", entry.Namespace, entry.Name, err) + } + return nil +} + +func (p *dnsRecordProvider) prepareEntry(domain string) *extensionsv1alpha.DNSRecord { + entry := &extensionsv1alpha.DNSRecord{} + entry.Name = "cert--" + domain + entry.Namespace = p.settings.Namespace + return entry +} + +func (p *dnsRecordProvider) checkDNSResourceReady(domain string, _ []string) bool { + entry := p.prepareEntry(domain) + obj, err := p.dnsrecordResources.Get_(entry) + if err != nil { + return true // no more waiting + } + entry = obj.Data().(*extensionsv1alpha.DNSRecord) + p.entries[domain] = entry + return entry.Status.LastOperation != nil && entry.Status.LastOperation.State == v1beta1.LastOperationStateSucceeded && + entry.Generation == entry.Status.ObservedGeneration +} + +func (p *dnsRecordProvider) failedDNSResourceReadyMessage(final bool) string { + if final { + var errs []error + for key, entry := range p.entries { + switch { + case entry.Status.LastOperation == nil: + errs = append(errs, fmt.Errorf("no provider found to apply DNSRecord for %s", key)) + case entry.Status.LastOperation.State == v1beta1.LastOperationStateSucceeded: + continue + case entry.Status.LastOperation.Description != "": + errs = append(errs, fmt.Errorf("DNS entry for %s has state %s (%s)", key, entry.Status.LastOperation.State, entry.Status.LastOperation.Description)) + default: + errs = append(errs, fmt.Errorf("DNS entry for %s has state %s", key, entry.Status.LastOperation.State)) + } + } + if len(errs) > 0 { + return "DNSRecord getting ready: " + errors.Join(errs...).Error() + } + } + return "DNSRecord getting ready" +} diff --git a/pkg/controller/issuer/certificate/reconciler.go b/pkg/controller/issuer/certificate/reconciler.go index 4386d310..613e6286 100644 --- a/pkg/controller/issuer/certificate/reconciler.go +++ b/pkg/controller/issuer/certificate/reconciler.go @@ -15,6 +15,8 @@ import ( "strings" "time" + extensionsv1alpha "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + "github.com/gardener/gardener/pkg/utils/gardener" "github.com/go-acme/lego/v4/certificate" corev1 "k8s.io/api/core/v1" apierrrors "k8s.io/apimachinery/pkg/api/errors" @@ -54,6 +56,10 @@ const ( AnnotationRevoked = api.GroupName + "/revoked" // AnnotationRequestedAt is the annotation for storing the timestamp when the certificate was requested AnnotationRequestedAt = api.GroupName + "/requestedAt" + // AnnotationDNSRecordProviderType is the annotation for providing the provider type for DNS records. + AnnotationDNSRecordProviderType = api.GroupName + "/dnsrecord-provider-type" + // AnnotationDNSRecordSecretRef is the annotation for providing the secret ref for DNS records. + AnnotationDNSRecordSecretRef = api.GroupName + "/dnsrecord-secret-ref" ) type backoffMode int @@ -118,6 +124,7 @@ func CertReconciler(c controller.Interface, support *core.Support) (reconcile.In if dnsOwnerID != "" { reconciler.dnsOwnerID = &dnsOwnerID } + reconciler.useDNSRecords, _ = c.GetBoolOption(core.OptUseDNSRecords) reconciler.cascadeDelete, _ = c.GetBoolOption(core.OptCascadeDelete) renewalWindow, err := c.GetDurationOption(core.OptRenewalWindow) @@ -157,6 +164,7 @@ type certReconciler struct { dnsNamespace *string dnsClass *string dnsOwnerID *string + useDNSRecords bool precheckNameservers []string additionalWait time.Duration propagationTimeout time.Duration @@ -171,7 +179,11 @@ type certReconciler struct { } func (r *certReconciler) Start() { - r.cleanupOrphanDNSEntriesFromOldChallenges() + if !r.useDNSRecords { + r.cleanupOrphanDNSEntriesFromOldChallenges() + } else { + r.cleanupOrphanDNSRecordsFromOldChallenges() + } r.cleanupOrphanOutdatedCertificateSecrets() r.garbageCollectorTicker = time.NewTicker(7 * 24 * time.Hour) @@ -460,6 +472,12 @@ func (r *certReconciler) obtainCertificateAndPendingACME(logctx logger.LogContex if r.dnsNamespace != nil { dnsSettings.Namespace = *r.dnsNamespace } + if r.useDNSRecords { + dnsSettings.DNSRecordSettings, err = createDNSRecordSettings(cert) + if err != nil { + return r.failed(logctx, obj, api.StateError, err) + } + } } targetDNSClass := "" if r.dnsClass != nil { @@ -1192,6 +1210,47 @@ func (r *certReconciler) cleanupOrphanDNSEntriesFromOldChallenges() { logger.Infof("issuer: cleanup: %d orphan DNS entries deleted", count) } +func (r *certReconciler) cleanupOrphanDNSRecordsFromOldChallenges() { + // find orphan dnsentries from DNSChallenges and try to delete them + // should only happen if cert-manager is terminated during running DNS challenge(s) + + recordsResource, err := r.dnsCluster.Resources().GetByExample(&extensionsv1alpha.DNSRecord{}) + if err != nil { + logger.Warnf("issuer: cleanupOrphanDNSRecordsFromOldChallenges failed with: %s", err) + return + } + var objects []resources.Object + if r.dnsNamespace != nil { + objects, err = recordsResource.Namespace(*r.dnsNamespace).List(metav1.ListOptions{}) + } else { + objects, err = recordsResource.List(metav1.ListOptions{}) + } + if err != nil { + logger.Warnf("issuer: cleanupOrphanDNSRecordsFromOldChallenges failed with: %s", err) + return + } + count := 0 + for _, obj := range objects { + challenge, _ := resources.GetAnnotation(obj.Data(), source.AnnotACMEDNSChallenge) + if challenge != "" { + if resources.SetAnnotation(obj.Data(), gardener.ConfirmationDeletion, "true") { + if _, err := recordsResource.Update(obj.Data()); err != nil { + logger.Warnf("issuer: annotating DNSRecord %s/%s failed: %w", obj.GetNamespace(), obj.GetName(), err) + continue + } + } + + err = recordsResource.Delete(obj.Data()) + if err != nil { + logger.Warnf("issuer: deleting DNSRecord %s/%s failed with: %s", obj.GetNamespace(), obj.GetName(), err) + continue + } + count++ + } + } + logger.Infof("issuer: cleanup: %d orphan DNSRecords deleted", count) +} + // cleanupOrphanOutdatedCertificateSecrets performs a garbage collection of orphan secrets. // A certificate secret is deleted if it is not referenced by a certificate custom resource and // if its TLS certificate is not valid since at least 14 days. @@ -1260,3 +1319,27 @@ func (r *certReconciler) cleanupOrphanOutdatedCertificateSecrets() { logger.Infof("issuer: cleanup-secrets: %d/%d orphan outdated certificate secrets deleted (%d total, %d backups, %d revoked)", deleted, outdated, len(secrets), backup, revoked) } + +func createDNSRecordSettings(cert *api.Certificate) (*legobridge.DNSRecordSettings, error) { + typ := cert.Annotations[AnnotationDNSRecordProviderType] + if typ == "" { + return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", AnnotationDNSRecordProviderType) + } + ref := cert.Annotations[AnnotationDNSRecordSecretRef] + if ref == "" { + return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", AnnotationDNSRecordSecretRef) + } + parts := strings.SplitN(ref, "/", 2) + var secretRef corev1.SecretReference + if len(parts) == 1 { + secretRef.Namespace = cert.Namespace + secretRef.Name = parts[0] + } else { + secretRef.Namespace = parts[0] + secretRef.Name = parts[1] + } + return &legobridge.DNSRecordSettings{ + Type: typ, + SecretRef: secretRef, + }, nil +} diff --git a/pkg/controller/issuer/controller.go b/pkg/controller/issuer/controller.go index 5542ed0b..33639745 100644 --- a/pkg/controller/issuer/controller.go +++ b/pkg/controller/issuer/controller.go @@ -31,9 +31,10 @@ func init() { DefaultedStringOption(core.OptDefaultIssuer, "default-issuer", "name of default issuer (from default cluster)"). DefaultedStringOption(core.OptIssuerNamespace, "default", "namespace to lookup issuers on default cluster"). StringOption(core.OptDefaultIssuerDomainRanges, "domain range restrictions when using default issuer separated by comma"). - StringOption(core.OptDNSNamespace, "namespace for creating challenge DNSEntries (in DNS cluster)"). + StringOption(core.OptDNSNamespace, "namespace for creating challenge DNSEntries or DNSRecords (in DNS cluster)"). StringOption(core.OptDNSClass, "class for creating challenge DNSEntries (in DNS cluster)"). StringOption(core.OptDNSOwnerID, "ownerId for creating challenge DNSEntries"). + BoolOption(core.OptUseDNSRecords, "if true, DNSRecords (using Gardener Provider extensions) are created instead of DNSEntries"). BoolOption(core.OptCascadeDelete, "If true, certificate secrets are deleted if dependent resources (certificate, ingress) are deleted"). BoolOption(core.OptACMEDeactivateAuthorizations, "if true authorizations are always deactivated after each ACME certificate request"). StringOption(source.OptClass, "Identifier used to differentiate responsible controllers for entries"). diff --git a/pkg/controller/issuer/core/const.go b/pkg/controller/issuer/core/const.go index cd42785a..e9842fd4 100644 --- a/pkg/controller/issuer/core/const.go +++ b/pkg/controller/issuer/core/const.go @@ -24,6 +24,8 @@ const ( OptDNSClass = "dns-class" // OptDNSOwnerID is the DNS owner identifier command line option. OptDNSOwnerID = "dns-owner-id" + // OptUseDNSRecords is the command line option to use DNSRecords instead of DNSEntries for DNS challenges. + OptUseDNSRecords = "use-dnsrecords" // OptDefaultIssuerDomainRanges are the domain ranges the default issuer is restricted to. OptDefaultIssuerDomainRanges = "default-issuer-domain-ranges" // OptRenewalWindow is the renewal window command line option. diff --git a/test/functional/basics.go b/test/functional/basics.go index 5632a47d..6c8f1092 100644 --- a/test/functional/basics.go +++ b/test/functional/basics.go @@ -9,6 +9,7 @@ package functional import ( "context" "crypto/x509" + "os" "time" "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1" @@ -281,6 +282,9 @@ func init() { func functestbasics(cfg *config.Config, iss *config.IssuerConfig) { _ = Describe("basics-"+iss.Name, func() { It("should work with "+iss.Name, func(_ context.Context) { + if os.Getenv("USE_DNSRECORDS") == "true" { + Skip("skipping for DNSRecords") + } manifestFilename, err := iss.CreateTempManifest("Manifest", basicTemplate) defer iss.DeleteTempManifest(manifestFilename) Ω(err).ShouldNot(HaveOccurred()) diff --git a/test/functional/dnsrecords.go b/test/functional/dnsrecords.go new file mode 100644 index 00000000..5379cea0 --- /dev/null +++ b/test/functional/dnsrecords.go @@ -0,0 +1,316 @@ +/* + * SPDX-FileCopyrightText: 2019 SAP SE or an SAP affiliate company and Gardener contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package functional + +import ( + "context" + "errors" + "os" + "time" + + "github.com/gardener/cert-management/pkg/apis/cert/v1alpha1" + "github.com/gardener/cert-management/test/functional/config" + dnsapi "github.com/gardener/external-dns-management/pkg/apis/dns/v1alpha1" + "github.com/gardener/gardener/pkg/apis/core/v1beta1" + extensionsv1alpha "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + "github.com/gardener/gardener/pkg/controllerutils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/kube-openapi/pkg/util/sets" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/gardener/controller-manager-library/pkg/resources" + "github.com/gardener/controller-manager-library/pkg/utils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gstruct" +) + +var dnsrecordsTemplate = ` +apiVersion: cert.gardener.cloud/v1alpha1 +kind: Issuer +metadata: + name: {{.Name}} + namespace: {{.Namespace}} +spec: +{{if eq .Type "acme"}} + acme: + server: {{.Server}} + email: {{.Email}} +{{if not .PrivateKey }} + autoRegistration: {{.AutoRegistration}} +{{end}} + privateKeySecretRef: + name: {{.Name}}-secret + namespace: {{.Namespace}} +{{if .ExternalAccountBinding }} + externalAccountBinding: + keyID: {{ .ExternalAccountBinding.KeyID }} + keySecretRef: + name: {{.Name}}-eab-secret + namespace: {{.Namespace}} +{{end}} +{{if .SkipDNSChallengeValidation }} + skipDNSChallengeValidation: true +{{end}} +{{end}} +{{if .ExternalAccountBinding }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{.Name}}-eab-secret + namespace: {{.Namespace}} +type: Opaque +data: + hmacKey: {{ .ExternalAccountBinding.HmacKey }} +{{end}} +{{if .PrivateKey }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{.Name}}-secret + namespace: {{.Namespace}} +type: Opaque +data: + privateKey: {{ .PrivateKey }} +{{end}} +--- +apiVersion: cert.gardener.cloud/v1alpha1 +kind: Certificate +metadata: + name: cert1 + namespace: {{.Namespace}} + annotations: + cert.gardener.cloud/dnsrecord-provider-type: dummy-type + cert.gardener.cloud/dnsrecord-secret-ref: dummy-ref +spec: + commonName: cert1.{{.Domain}} + dnsNames: + - cert1a.{{.Domain}} + - cert1b.{{.Domain}} + secretName: cert1-secret + issuerRef: + name: {{.Name}} +` + +func init() { + utils.Must(resources.Register(v1alpha1.SchemeBuilder)) + utils.Must(resources.Register(extensionsv1alpha.SchemeBuilder)) + utils.Must(resources.Register(dnsapi.SchemeBuilder)) + addIssuerTests(functestdnsrecords) +} + +func functestdnsrecords(cfg *config.Config, iss *config.IssuerConfig) { + _ = Describe("basics-"+iss.Name, Ordered, func() { + var cancelFuncTranslator context.CancelFunc + BeforeAll(func() { + cancelFuncTranslator = startDNSRecordToDNSEntryTranslator("default", cfg.DNSKubeConfig) + }) + AfterAll(func() { + if cancelFuncTranslator != nil { + cancelFuncTranslator() + } + }) + It("should work with "+iss.Name, func(_ context.Context) { + if os.Getenv("USE_DNSRECORDS") != "true" { + Skip("skipping as not using DNSRecords") + } + manifestFilename, err := iss.CreateTempManifest("Manifest", dnsrecordsTemplate) + defer iss.DeleteTempManifest(manifestFilename) + Ω(err).ShouldNot(HaveOccurred()) + + u := cfg.Utils + + err = u.AwaitKubectlGetCRDs("issuers.cert.gardener.cloud", "certificates.cert.gardener.cloud") + Ω(err).ShouldNot(HaveOccurred()) + + err = u.KubectlApply(manifestFilename) + Ω(err).ShouldNot(HaveOccurred()) + + err = u.AwaitIssuerReady(iss.Name) + Ω(err).ShouldNot(HaveOccurred()) + + cert1Name := entryName(iss, "1") + err = u.AwaitCertReady(cert1Name) + Ω(err).ShouldNot(HaveOccurred()) + + itemMap, err := u.KubectlGetAllCertificates() + Ω(err).ShouldNot(HaveOccurred()) + + Ω(itemMap).Should(MatchKeys(IgnoreExtras, Keys{ + entryName(iss, "1"): MatchKeys(IgnoreExtras, Keys{ + "metadata": MatchKeys(IgnoreExtras, Keys{ + "labels": MatchKeys(IgnoreExtras, Keys{ + "cert.gardener.cloud/hash": HavePrefix(""), + }), + }), + "spec": MatchKeys(IgnoreExtras, Keys{ + "secretRef": MatchKeys(IgnoreExtras, Keys{ + "name": HavePrefix(entryName(iss, "1") + "-"), + "namespace": Equal(iss.Namespace), + }), + }), + "status": MatchKeys(IgnoreExtras, Keys{ + "commonName": Equal(dnsName(iss, "cert1")), + "dnsNames": And(HaveLen(2), ContainElement(dnsName(iss, "cert1a")), ContainElement(dnsName(iss, "cert1b"))), + "state": Equal("Ready"), + "expirationDate": HavePrefix("20"), + }), + }), + })) + + err = u.KubectlDelete(manifestFilename) + Ω(err).ShouldNot(HaveOccurred()) + + err = u.AwaitCertDeleted(cert1Name) + Ω(err).ShouldNot(HaveOccurred()) + + err = u.AwaitIssuerDeleted(iss.Name) + Ω(err).ShouldNot(HaveOccurred()) + }, SpecTimeout(180*time.Second)) + }) +} + +func startDNSRecordToDNSEntryTranslator(namespace, dnskubeconfig string) context.CancelFunc { + var collectedErrors []error + + reportError := func(description string, err error) { + collectedErrors = append(collectedErrors, err) + println(description, "failed with:", err.Error()) + } + + config, err := clientcmd.BuildConfigFromFlags("", dnskubeconfig) + if err != nil { + reportError("BuildConfigFromFlags", err) + } + + c, err := client.New(config, client.Options{ + Scheme: resources.DefaultScheme(), + }) + if err != nil { + reportError("client.New", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + entries := map[string]*dnsapi.DNSEntry{} + go func() { + for { + select { + case <-ctx.Done(): + if len(collectedErrors) > 0 { + panic(errors.Join(collectedErrors...)) + } + return + default: + } + + list := &extensionsv1alpha.DNSRecordList{} + if err := c.List(ctx, list, client.InNamespace(namespace)); err != nil { + reportError("List DNSRecords", err) + } + + found := sets.String{} + for _, record := range list.Items { + if record.Spec.Type != "dummy-type" || + record.Spec.SecretRef.Name != "dummy-ref" || + record.Spec.SecretRef.Namespace != namespace || + record.Spec.RecordType != extensionsv1alpha.DNSRecordTypeTXT { + println("ignoring", record.Name) + continue + } + found.Insert(record.Name) + if entry := entries[record.Name]; entry == nil { + println("create", record.Name) + if err := addFinalizer(ctx, c, record); err != nil { + reportError("addFinalizer", err) + } + if entry, err := createDNSEntry(ctx, c, record); err != nil { + reportError("createDNSEntry", err) + } else { + entries[record.Name] = entry + } + } else if record.DeletionTimestamp != nil { + if err := c.Delete(ctx, entry); err != nil { + reportError("delete DNSEntry", err) + } else { + delete(entries, record.Name) + } + if err := removeFinalizer(ctx, c, record); err != nil { + reportError("removeFinalizer", err) + } + } else { + entry := &dnsapi.DNSEntry{} + if err := c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: record.Name}, entry); err != nil { + reportError("get DNSEntry", err) + } + if entry.Generation == entry.Status.ObservedGeneration && record.Status.LastOperation == nil { + switch entry.Status.State { + case "Ready": + record.Status.LastOperation = &v1beta1.LastOperation{ + Description: "ready", + LastUpdateTime: metav1.Now(), + Progress: 100, + State: "Succeeded", + Type: "Create", + } + case "Error": + record.Status.LastOperation = &v1beta1.LastOperation{ + Description: "failed", + LastUpdateTime: metav1.Now(), + Progress: 100, + State: "Error", + Type: "Create", + } + } + if record.Status.LastOperation != nil { + if err := c.Status().Update(ctx, &record); err != nil { + reportError("record status update", err) + } + } + } + } + } + + for name, entry := range entries { + if found.Has(name) { + continue + } + if err := c.Delete(ctx, entry); err != nil { + reportError("delete DNSEntry (cleanup)", err) + } + } + time.Sleep(500 * time.Millisecond) + } + }() + println("startDNSRecordToDNSEntryTranslator started") + return cancel +} + +func addFinalizer(ctx context.Context, c client.Client, record extensionsv1alpha.DNSRecord) error { + return controllerutils.AddFinalizers(ctx, c, &record, "cert.gardener.cloud/test") +} + +func removeFinalizer(ctx context.Context, c client.Client, record extensionsv1alpha.DNSRecord) error { + return controllerutils.RemoveFinalizers(ctx, c, &record, "cert.gardener.cloud/test") +} + +func createDNSEntry(ctx context.Context, c client.Client, record extensionsv1alpha.DNSRecord) (*dnsapi.DNSEntry, error) { + entry := &dnsapi.DNSEntry{ + ObjectMeta: metav1.ObjectMeta{ + Name: record.Name, + Namespace: record.Namespace, + }, + Spec: dnsapi.DNSEntrySpec{ + DNSName: record.Spec.Name, + Text: record.Spec.Values, + }, + } + err := c.Create(ctx, entry) + return entry, err +} diff --git a/test/functional/resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml b/test/functional/resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml new file mode 100644 index 00000000..62800170 --- /dev/null +++ b/test/functional/resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml @@ -0,0 +1,282 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: dnsrecords.extensions.gardener.cloud +spec: + group: extensions.gardener.cloud + names: + kind: DNSRecord + listKind: DNSRecordList + plural: dnsrecords + shortNames: + - dns + singular: dnsrecord + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The DNS record provider type. + jsonPath: .spec.type + name: Type + type: string + - description: The DNS record domain name. + jsonPath: .spec.name + name: Domain Name + type: string + - description: The DNS record type (A, CNAME, or TXT). + jsonPath: .spec.recordType + name: Record Type + type: string + - jsonPath: .status.lastOperation.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: DNSRecord is a specification for a DNSRecord resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + Specification of the DNSRecord. + If the object's deletion timestamp is set, this field is immutable. + properties: + name: + description: Name is the fully qualified domain name, e.g. "api.". This field is immutable. + type: string + providerConfig: + description: ProviderConfig is the provider specific configuration. + type: object + x-kubernetes-preserve-unknown-fields: true + recordType: + description: RecordType is the DNS record type. Only A, CNAME, and + TXT records are currently supported. This field is immutable. + type: string + region: + description: |- + Region is the region of this DNS record. If not specified, the region specified in SecretRef will be used. + If that is also not specified, the extension controller will use its default region. + type: string + secretRef: + description: SecretRef is a reference to a secret that contains the + cloud provider specific credentials. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + ttl: + description: TTL is the time to live in seconds. Defaults to 120. + format: int64 + type: integer + type: + description: Type contains the instance of the resource's kind. + type: string + values: + description: Values is a list of IP addresses for A records, a single + hostname for CNAME records, or a list of texts for TXT records. + items: + type: string + type: array + zone: + description: |- + Zone is the DNS hosted zone of this DNS record. If not specified, it will be determined automatically by + getting all hosted zones of the account and searching for the longest zone name that is a suffix of Name. + type: string + required: + - name + - recordType + - secretRef + - type + - values + type: object + status: + description: DNSRecordStatus is the status of a DNSRecord resource. + properties: + conditions: + description: Conditions represents the latest available observations + of a Seed's current state. + items: + description: Condition holds the information about the state of + a resource. + properties: + codes: + description: Well-defined error codes in case the condition + reports a problem. + items: + description: ErrorCode is a string alias. + type: string + type: array + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + lastUpdateTime: + description: Last time the condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of the condition. + type: string + required: + - lastTransitionTime + - lastUpdateTime + - message + - reason + - status + - type + type: object + type: array + lastError: + description: LastError holds information about the last occurred error + during an operation. + properties: + codes: + description: Well-defined error codes of the last error(s). + items: + description: ErrorCode is a string alias. + type: string + type: array + description: + description: A human readable message indicating details about + the last error. + type: string + lastUpdateTime: + description: Last time the error was reported + format: date-time + type: string + taskID: + description: ID of the task which caused this last error + type: string + required: + - description + type: object + lastOperation: + description: LastOperation holds information about the last operation + on the resource. + properties: + description: + description: A human readable message indicating details about + the last operation. + type: string + lastUpdateTime: + description: Last time the operation state transitioned from one + to another. + format: date-time + type: string + progress: + description: The progress in percentage (0-100) of the last operation. + format: int32 + type: integer + state: + description: Status of the last operation, one of Aborted, Processing, + Succeeded, Error, Failed. + type: string + type: + description: Type of the last operation, one of Create, Reconcile, + Delete, Migrate, Restore. + type: string + required: + - description + - lastUpdateTime + - progress + - state + - type + type: object + observedGeneration: + description: ObservedGeneration is the most recent generation observed + for this resource. + format: int64 + type: integer + providerStatus: + description: ProviderStatus contains provider-specific status. + type: object + x-kubernetes-preserve-unknown-fields: true + resources: + description: Resources holds a list of named resource references that + can be referred to in the state by their names. + items: + description: NamedResourceReference is a named reference to a resource. + properties: + name: + description: Name of the resource reference. + type: string + resourceRef: + description: ResourceRef is a reference to a resource. + properties: + apiVersion: + description: apiVersion is the API version of the referent + type: string + kind: + description: 'kind is the kind of the referent; More info: + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'name is the name of the referent; More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - name + - resourceRef + type: object + type: array + state: + description: State can be filled by the operating controller with + what ever data it needs. + type: object + x-kubernetes-preserve-unknown-fields: true + zone: + description: Zone is the DNS hosted zone of this DNS record. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/test/functional/run.sh b/test/functional/run.sh index 0b861be6..c6dbb5b5 100755 --- a/test/functional/run.sh +++ b/test/functional/run.sh @@ -15,6 +15,7 @@ cd $SCRIPT_BASEDIR FUNCTEST_CONFIG=functest-config.yaml RUN_CONTROLLER=true +USE_DNSRECORDS=false usage() { @@ -34,6 +35,7 @@ Options: -v verbose output of script (not test itself) -f path to functest configuration file (defaults to $FUNCTEST_CONFIG) --no-controller do not start the cert-controller-manager + --use-dnsrecords use DNS records instead of DNS entries --dns kubeconfig for writing temporary DNS entries of challenges (default to $DNS_KUBECONFIG or $KUBECONFIG) --dns-domain DNS domain suffix to use for certificates (must have a DNS provider) For options of ginkgo run: @@ -64,6 +66,9 @@ while [ "$1" != "" ]; do --no-controller ) shift RUN_CONTROLLER=false ;; + --use-dnsrecords ) shift + USE_DNSRECORDS=true + ;; --dns ) shift DNS_KUBECONFIG=$1 shift @@ -194,14 +199,19 @@ fi if [ "$RUN_CONTROLLER" == "true" ]; then go build -o $ROOTDIR/cert-controller-manager $ROOTDIR/cmd/cert-controller-manager - $ROOTDIR/cert-controller-manager --dns $DNS_KUBECONFIG >/tmp/functest-cert-controller-manager.log 2>&1 & + $ROOTDIR/cert-controller-manager --dns $DNS_KUBECONFIG --use-dnsrecords=$USE_DNSRECORDS --omit-lease >/tmp/functest-cert-controller-manager.log 2>&1 & PID_CONTROLLER=$! fi # install ginkgo go install github.com/onsi/ginkgo/v2/ginkgo -FUNCTEST_CONFIG=$FUNCTEST_CONFIG DNS_KUBECONFIG=$DNS_KUBECONFIG DNS_DOMAIN=$DNS_DOMAIN ginkgo -p "$@" +if [ "$USE_DNSRECORDS" == "true" ]; then + echo "USE_DNSRECORDS=true" + kubectl --kubeconfig=$DNS_KUBECONFIG apply -f resources/10-crd-extensions.gardener.cloud_dnsrecords.yaml +fi + +FUNCTEST_CONFIG=$FUNCTEST_CONFIG DNS_KUBECONFIG=$DNS_KUBECONFIG DNS_DOMAIN=$DNS_DOMAIN USE_DNSRECORDS=$USE_DNSRECORDS ginkgo -p "$@" RETCODE=$? From b597c5a80f06815a4356539fd2ff8dd633e90883 Mon Sep 17 00:00:00 2001 From: Martin Weindel Date: Tue, 7 May 2024 15:07:23 +0200 Subject: [PATCH 2/3] support for source objects --- README.md | 357 ++++++++++-------- examples/30-cert-simple.yaml | 3 + examples/40-gateway-gateway-api.yaml | 3 + examples/40-ingress-echoheaders.yaml | 3 + examples/40-service-loadbalancer.yaml | 4 + pkg/cert/source/controller.go | 5 + pkg/cert/source/defaults.go | 1 + pkg/cert/source/interface.go | 1 + pkg/cert/source/reconciler.go | 10 + pkg/cert/source/utils.go | 15 +- .../issuer/certificate/reconciler.go | 12 +- .../gateways/gatewayapi/handler_test.go | 22 +- pkg/controller/source/helper.go | 2 + 13 files changed, 266 insertions(+), 172 deletions(-) diff --git a/README.md b/README.md index 78a6618b..a8c2cb2f 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Currently, the `cert-controller-manager` supports certificate authorities via: - [Revoking certificates with renewal](#revoking-certificates-with-renewal) - [Checking OCSP revocation using OpenSSL](#checking-ocsp-revocation-using-openssl) - [Metrics](#metrics) + - [Using DNSRecords](#using-dnsrecords) - [Troubleshooting](#troubleshooting) - [Development](#development) @@ -495,49 +496,52 @@ See also [examples/40-ingress-echoheaders.yaml](./examples/40-ingress-echoheader pathType: Prefix ``` -2. Annotate the Ingress Resource - - The annotation `cert.gardener.cloud/purpose: managed` instructs `cert-controller-manager` to handle certificate issuance for the domains found in labeled Ingress. - - ```yaml - apiVersion: networking.k8s.io/v1 - kind: Ingress - metadata: - name: tls-example-ingress - annotations: - # Let Gardener manage certificates for this Ingress. - cert.gardener.cloud/purpose: managed - #dns.gardener.cloud/class: garden # needed on Gardener shoot clusters for managed DNS record creation (if not covered by `*.ingress...shoot.example.com) - #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from spec.tls[].hosts is used as common name - #cert.gardener.cloud/dnsnames: "" # optional, if not specified the names from spec.tls[].hosts are used - #cert.gardener.cloud/follow-cname: "true" # optional, to activate CNAME following for the DNS challenge - #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret - #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers) - #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) - #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' - #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" - spec: - tls: - - hosts: - - echoheaders.demo.mydomain.com - secretName: cert-echoheaders - rules: - - host: echoheaders.demo.mydomain.com - http: - paths: - - backend: - service: - name: echoheaders - port: - number: 80 - path: / - pathType: Prefix - ``` + 2. Annotate the Ingress Resource + + The annotation `cert.gardener.cloud/purpose: managed` instructs `cert-controller-manager` to handle certificate issuance for the domains found in labeled Ingress. + + ```yaml + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: tls-example-ingress + annotations: + # Let Gardener manage certificates for this Ingress. + cert.gardener.cloud/purpose: managed + #dns.gardener.cloud/class: garden # needed on Gardener shoot clusters for managed DNS record creation (if not covered by `*.ingress...shoot.example.com) + #cert.gardener.cloud/commonname: "*.demo.mydomain.com" # optional, if not specified the first name from spec.tls[].hosts is used as common name + #cert.gardener.cloud/dnsnames: "" # optional, if not specified the names from spec.tls[].hosts are used + #cert.gardener.cloud/follow-cname: "true" # optional, to activate CNAME following for the DNS challenge + #cert.gardener.cloud/secret-labels: "key1=value1,key2=value2" # optional labels for the certificate secret + #cert.gardener.cloud/issuer: issuer-name # optional to specify custom issuer (use namespace/name for shoot issuers) + #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) + #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' + #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret + spec: + tls: + - hosts: + - echoheaders.demo.mydomain.com + secretName: cert-echoheaders + rules: + - host: echoheaders.demo.mydomain.com + http: + paths: + - backend: + service: + name: echoheaders + port: + number: 80 + path: / + pathType: Prefix + ``` - The annotation `cert.gardener.cloud/commonname` can be set to explicitly specify the common name. - If no set, the first name of `spec.tls.hosts` is used as common name. - The annotation `cert.gardener.cloud/dnsnames` can be used to explicitly specify the alternative DNS names. - If no set, the names of `spec.tls.hosts` are used. + The annotation `cert.gardener.cloud/commonname` can be set to explicitly specify the common name. + If no set, the first name of `spec.tls.hosts` is used as common name. + The annotation `cert.gardener.cloud/dnsnames` can be used to explicitly specify the alternative DNS names. + If no set, the names of `spec.tls.hosts` are used. 3. Check status @@ -570,6 +574,9 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret dns.gardener.cloud/ttl: "600" name: test-service namespace: default @@ -695,6 +702,9 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret name: my-gateway namespace: default spec: @@ -749,6 +759,9 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret name: my-gateway namespace: default spec: @@ -801,119 +814,147 @@ Usage: cert-controller-manager [flags] Flags: - --accepted-maintainers string accepted maintainer key(s) for crds - --acme-deactivate-authorizations if true authorizations are always deactivated after each ACME certificate request - --allow-target-issuers If true, issuers are also watched on the target cluster - --bind-address-http string HTTP server bind address - --cascade-delete If true, certificate secrets are deleted if dependent resources (certificate, ingress) are deleted - --cert-class string Identifier used to differentiate responsible controllers for entries - --cert-target-class string Identifier used to differentiate responsible dns controllers for target entries - --config string config file - -c, --controllers string comma separated list of controllers to start (,,all) - --cpuprofile string set file for cpu profiling - --default-ecdsa-private-key-size int Default certificate private key size for 'ecdsa' algorithm. - --default-issuer string name of default issuer (from default cluster) - --default-issuer-domain-ranges string domain range restrictions when using default issuer separated by comma - --default-private-key-algorithm string default algorithm for certificate private keys - --default-requests-per-day-quota int Default value for requestsPerDayQuota if not set explicitly in the issuer spec. - --default-rsa-private-key-size int Default certificate private key size for 'rsa' algorithm. - --default.pool.resync-period duration Period for resynchronization for pool default - --default.pool.size int Worker pool size for pool default - --disable-namespace-restriction disable access restriction for namespace local access only - --dns string cluster for writing challenge DNS entries - --dns-class string class for creating challenge DNSEntries (in DNS cluster) - --dns-namespace string namespace for creating challenge DNSEntries (in DNS cluster) - --dns-owner-id string ownerId for creating challenge DNSEntries - --dns.disable-deploy-crds disable deployment of required crds for cluster dns - --dns.id string id for cluster dns - --dns.migration-ids string migration id for cluster dns - --force-crd-update enforce update of crds even they are unmanaged - --grace-period duration inactivity grace period for detecting end of cleanup for shutdown - -h, --help help for cert-controller-manager - --ingress-cert.cert-class string Identifier used to differentiate responsible controllers for entries of controller ingress-cert - --ingress-cert.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller ingress-cert - --ingress-cert.default.pool.resync-period duration Period for resynchronization for pool default of controller ingress-cert - --ingress-cert.default.pool.size int Worker pool size for pool default of controller ingress-cert - --ingress-cert.pool.resync-period duration Period for resynchronization of controller ingress-cert - --ingress-cert.pool.size int Worker pool size of controller ingress-cert - --ingress-cert.target-name-prefix string name prefix in target namespace for cross cluster generation of controller ingress-cert - --ingress-cert.target-namespace string target namespace for cross cluster generation of controller ingress-cert - --ingress-cert.targets.pool.size int Worker pool size for pool targets of controller ingress-cert - --issuer-namespace string namespace to lookup issuers on default cluster - --issuer.acme-deactivate-authorizations if true authorizations are always deactivated after each ACME certificate request of controller issuer - --issuer.allow-target-issuers If true, issuers are also watched on the target cluster of controller issuer - --issuer.cascade-delete If true, certificate secrets are deleted if dependent resources (certificate, ingress) are deleted of controller issuer - --issuer.cert-class string Identifier used to differentiate responsible controllers for entries of controller issuer - --issuer.default-ecdsa-private-key-size int Default certificate private key size for 'ecdsa' algorithm. of controller issuer - --issuer.default-issuer string name of default issuer (from default cluster) of controller issuer - --issuer.default-issuer-domain-ranges string domain range restrictions when using default issuer separated by comma of controller issuer - --issuer.default-private-key-algorithm string default algorithm for certificate private keys of controller issuer - --issuer.default-requests-per-day-quota int Default value for requestsPerDayQuota if not set explicitly in the issuer spec. of controller issuer - --issuer.default-rsa-private-key-size int Default certificate private key size for 'rsa' algorithm. of controller issuer - --issuer.default.pool.resync-period duration Period for resynchronization for pool default of controller issuer - --issuer.default.pool.size int Worker pool size for pool default of controller issuer - --issuer.dns-class string class for creating challenge DNSEntries (in DNS cluster) of controller issuer - --issuer.dns-namespace string namespace for creating challenge DNSEntries (in DNS cluster) of controller issuer - --issuer.dns-owner-id string ownerId for creating challenge DNSEntries of controller issuer - --issuer.issuer-namespace string namespace to lookup issuers on default cluster of controller issuer - --issuer.issuers.pool.size int Worker pool size for pool issuers of controller issuer - --issuer.pool.resync-period duration Period for resynchronization of controller issuer - --issuer.pool.size int Worker pool size of controller issuer - --issuer.precheck-additional-wait duration additional wait time after DNS propagation check of controller issuer - --issuer.precheck-nameservers string Default DNS nameservers used for checking DNS propagation. If explicity set empty, it is tried to read them from /etc/resolv.conf of controller issuer - --issuer.propagation-timeout duration propagation timeout for DNS challenge of controller issuer - --issuer.renewal-overdue-window duration certificate is counted as 'renewal overdue' if its validity period is shorter (metrics cert_management_overdue_renewal_certificates) of controller issuer - --issuer.renewal-window duration certificate is renewed if its validity period is shorter of controller issuer - --issuer.revocations.pool.size int Worker pool size for pool revocations of controller issuer - --issuer.secrets.pool.size int Worker pool size for pool secrets of controller issuer - --issuers.pool.size int Worker pool size for pool issuers - --kubeconfig string default cluster access - --kubeconfig.disable-deploy-crds disable deployment of required crds for cluster default - --kubeconfig.id string id for cluster default - --kubeconfig.migration-ids string migration id for cluster default - --lease-duration duration lease duration - --lease-name string name for lease object - --lease-renew-deadline duration lease renew deadline - --lease-resource-lock string determines which resource lock to use for leader election, defaults to 'leases' - --lease-retry-period duration lease retry period - -D, --log-level string logrus log level - --maintainer string maintainer key for crds (default "cert-controller-manager") - --name string name used for controller manager (default "cert-controller-manager") - --namespace string namespace for lease (default "kube-system") - -n, --namespace-local-access-only enable access restriction for namespace local access only (deprecated) - --omit-lease omit lease for development - --plugin-file string directory containing go plugins - --pool.resync-period duration Period for resynchronization - --pool.size int Worker pool size - --precheck-additional-wait duration additional wait time after DNS propagation check - --precheck-nameservers string Default DNS nameservers used for checking DNS propagation. If explicity set empty, it is tried to read them from /etc/resolv.conf - --propagation-timeout duration propagation timeout for DNS challenge - --renewal-overdue-window duration certificate is counted as 'renewal overdue' if its validity period is shorter (metrics cert_management_overdue_renewal_certificates) - --renewal-window duration certificate is renewed if its validity period is shorter - --revocations.pool.size int Worker pool size for pool revocations - --secrets.pool.size int Worker pool size for pool secrets - --server-port-http int HTTP server port (serving /healthz, /metrics, ...) - --service-cert.cert-class string Identifier used to differentiate responsible controllers for entries of controller service-cert - --service-cert.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller service-cert - --service-cert.default.pool.resync-period duration Period for resynchronization for pool default of controller service-cert - --service-cert.default.pool.size int Worker pool size for pool default of controller service-cert - --service-cert.pool.resync-period duration Period for resynchronization of controller service-cert - --service-cert.pool.size int Worker pool size of controller service-cert - --service-cert.target-name-prefix string name prefix in target namespace for cross cluster generation of controller service-cert - --service-cert.target-namespace string target namespace for cross cluster generation of controller service-cert - --service-cert.targets.pool.size int Worker pool size for pool targets of controller service-cert - --source string source cluster to watch for ingresses and services - --source.disable-deploy-crds disable deployment of required crds for cluster source - --source.id string id for cluster source - --source.migration-ids string migration id for cluster source - --target string target cluster for certificates - --target-name-prefix string name prefix in target namespace for cross cluster generation - --target-namespace string target namespace for cross cluster generation - --target.disable-deploy-crds disable deployment of required crds for cluster target - --target.id string id for cluster target - --target.migration-ids string migration id for cluster target - --targets.pool.size int Worker pool size for pool targets - -v, --version version for cert-controller-manager + --accepted-maintainers string accepted maintainer key(s) for crds + --acme-deactivate-authorizations if true authorizations are always deactivated after each ACME certificate request + --allow-target-issuers If true, issuers are also watched on the target cluster + --bind-address-http string HTTP server bind address + --cascade-delete If true, certificate secrets are deleted if dependent resources (certificate, ingress) are deleted + --cert-class string Identifier used to differentiate responsible controllers for entries + --cert-target-class string Identifier used to differentiate responsible dns controllers for target entries + --config string config file + -c, --controllers string comma separated list of controllers to start (,,all) + --cpuprofile string set file for cpu profiling + --default-ecdsa-private-key-size int Default certificate private key size for 'ecdsa' algorithm. + --default-issuer string name of default issuer (from default cluster) + --default-issuer-domain-ranges string domain range restrictions when using default issuer separated by comma + --default-private-key-algorithm string default algorithm for certificate private keys + --default-requests-per-day-quota int Default value for requestsPerDayQuota if not set explicitly in the issuer spec. + --default-rsa-private-key-size int Default certificate private key size for 'rsa' algorithm. + --default.pool.resync-period duration Period for resynchronization for pool default + --default.pool.size int Worker pool size for pool default + --disable-namespace-restriction disable access restriction for namespace local access only + --dns string cluster for writing challenge DNSEntries or DNSRecords + --dns-class string class for creating challenge DNSEntries (in DNS cluster) + --dns-namespace string namespace for creating challenge DNSEntries or DNSRecords (in DNS cluster) + --dns-owner-id string ownerId for creating challenge DNSEntries + --dns.disable-deploy-crds disable deployment of required crds for cluster dns + --dns.id string id for cluster dns + --dns.migration-ids string migration id for cluster dns + --force-crd-update enforce update of crds even they are unmanaged + --grace-period duration inactivity grace period for detecting end of cleanup for shutdown + -h, --help help for cert-controller-manager + --httproutes.pool.size int Worker pool size for pool httproutes + --ingress-cert.cert-class string Identifier used to differentiate responsible controllers for entries of controller ingress-cert + --ingress-cert.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller ingress-cert + --ingress-cert.default.pool.resync-period duration Period for resynchronization for pool default of controller ingress-cert + --ingress-cert.default.pool.size int Worker pool size for pool default of controller ingress-cert + --ingress-cert.pool.resync-period duration Period for resynchronization of controller ingress-cert + --ingress-cert.pool.size int Worker pool size of controller ingress-cert + --ingress-cert.target-name-prefix string name prefix in target namespace for cross cluster generation of controller ingress-cert + --ingress-cert.target-namespace string target namespace for cross cluster generation of controller ingress-cert + --ingress-cert.targets.pool.size int Worker pool size for pool targets of controller ingress-cert + --issuer-namespace string namespace to lookup issuers on default cluster + --issuer.acme-deactivate-authorizations if true authorizations are always deactivated after each ACME certificate request of controller issuer + --issuer.allow-target-issuers If true, issuers are also watched on the target cluster of controller issuer + --issuer.cascade-delete If true, certificate secrets are deleted if dependent resources (certificate, ingress) are deleted of controller issuer + --issuer.cert-class string Identifier used to differentiate responsible controllers for entries of controller issuer + --issuer.default-ecdsa-private-key-size int Default certificate private key size for 'ecdsa' algorithm. of controller issuer + --issuer.default-issuer string name of default issuer (from default cluster) of controller issuer + --issuer.default-issuer-domain-ranges string domain range restrictions when using default issuer separated by comma of controller issuer + --issuer.default-private-key-algorithm string default algorithm for certificate private keys of controller issuer + --issuer.default-requests-per-day-quota int Default value for requestsPerDayQuota if not set explicitly in the issuer spec. of controller issuer + --issuer.default-rsa-private-key-size int Default certificate private key size for 'rsa' algorithm. of controller issuer + --issuer.default.pool.resync-period duration Period for resynchronization for pool default of controller issuer + --issuer.default.pool.size int Worker pool size for pool default of controller issuer + --issuer.dns-class string class for creating challenge DNSEntries (in DNS cluster) of controller issuer + --issuer.dns-namespace string namespace for creating challenge DNSEntries or DNSRecords (in DNS cluster) of controller issuer + --issuer.dns-owner-id string ownerId for creating challenge DNSEntries of controller issuer + --issuer.issuer-namespace string namespace to lookup issuers on default cluster of controller issuer + --issuer.issuers.pool.size int Worker pool size for pool issuers of controller issuer + --issuer.pool.resync-period duration Period for resynchronization of controller issuer + --issuer.pool.size int Worker pool size of controller issuer + --issuer.precheck-additional-wait duration additional wait time after DNS propagation check of controller issuer + --issuer.precheck-nameservers string Default DNS nameservers used for checking DNS propagation. If explicity set empty, it is tried to read them from /etc/resolv.conf of controller issuer + --issuer.propagation-timeout duration propagation timeout for DNS challenge of controller issuer + --issuer.renewal-overdue-window duration certificate is counted as 'renewal overdue' if its validity period is shorter (metrics cert_management_overdue_renewal_certificates) of controller issuer + --issuer.renewal-window duration certificate is renewed if its validity period is shorter of controller issuer + --issuer.revocations.pool.size int Worker pool size for pool revocations of controller issuer + --issuer.secrets.pool.size int Worker pool size for pool secrets of controller issuer + --issuer.use-dnsrecords if true, DNSRecords (using Gardener Provider extensions) are created instead of DNSEntries of controller issuer + --issuers.pool.size int Worker pool size for pool issuers + --istio-gateways-dns.cert-class string Identifier used to differentiate responsible controllers for entries of controller istio-gateways-dns + --istio-gateways-dns.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller istio-gateways-dns + --istio-gateways-dns.default.pool.resync-period duration Period for resynchronization for pool default of controller istio-gateways-dns + --istio-gateways-dns.default.pool.size int Worker pool size for pool default of controller istio-gateways-dns + --istio-gateways-dns.pool.resync-period duration Period for resynchronization of controller istio-gateways-dns + --istio-gateways-dns.pool.size int Worker pool size of controller istio-gateways-dns + --istio-gateways-dns.target-name-prefix string name prefix in target namespace for cross cluster generation of controller istio-gateways-dns + --istio-gateways-dns.target-namespace string target namespace for cross cluster generation of controller istio-gateways-dns + --istio-gateways-dns.targets.pool.size int Worker pool size for pool targets of controller istio-gateways-dns + --istio-gateways-dns.targetsources.pool.size int Worker pool size for pool targetsources of controller istio-gateways-dns + --istio-gateways-dns.virtualservices.pool.size int Worker pool size for pool virtualservices of controller istio-gateways-dns + --k8s-gateways-dns.cert-class string Identifier used to differentiate responsible controllers for entries of controller k8s-gateways-dns + --k8s-gateways-dns.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller k8s-gateways-dns + --k8s-gateways-dns.default.pool.resync-period duration Period for resynchronization for pool default of controller k8s-gateways-dns + --k8s-gateways-dns.default.pool.size int Worker pool size for pool default of controller k8s-gateways-dns + --k8s-gateways-dns.httproutes.pool.size int Worker pool size for pool httproutes of controller k8s-gateways-dns + --k8s-gateways-dns.pool.resync-period duration Period for resynchronization of controller k8s-gateways-dns + --k8s-gateways-dns.pool.size int Worker pool size of controller k8s-gateways-dns + --k8s-gateways-dns.target-name-prefix string name prefix in target namespace for cross cluster generation of controller k8s-gateways-dns + --k8s-gateways-dns.target-namespace string target namespace for cross cluster generation of controller k8s-gateways-dns + --k8s-gateways-dns.targets.pool.size int Worker pool size for pool targets of controller k8s-gateways-dns + --kubeconfig string default cluster access + --kubeconfig.disable-deploy-crds disable deployment of required crds for cluster default + --kubeconfig.id string id for cluster default + --kubeconfig.migration-ids string migration id for cluster default + --lease-duration duration lease duration + --lease-name string name for lease object + --lease-renew-deadline duration lease renew deadline + --lease-resource-lock string determines which resource lock to use for leader election, defaults to 'leases' + --lease-retry-period duration lease retry period + -D, --log-level string logrus log level + --maintainer string maintainer key for crds (default "cert-controller-manager") + --name string name used for controller manager (default "cert-controller-manager") + --namespace string namespace for lease (default "kube-system") + -n, --namespace-local-access-only enable access restriction for namespace local access only (deprecated) + --omit-lease omit lease for development + --plugin-file string directory containing go plugins + --pool.resync-period duration Period for resynchronization + --pool.size int Worker pool size + --precheck-additional-wait duration additional wait time after DNS propagation check + --precheck-nameservers string Default DNS nameservers used for checking DNS propagation. If explicity set empty, it is tried to read them from /etc/resolv.conf + --propagation-timeout duration propagation timeout for DNS challenge + --renewal-overdue-window duration certificate is counted as 'renewal overdue' if its validity period is shorter (metrics cert_management_overdue_renewal_certificates) + --renewal-window duration certificate is renewed if its validity period is shorter + --revocations.pool.size int Worker pool size for pool revocations + --secrets.pool.size int Worker pool size for pool secrets + --server-port-http int HTTP server port (serving /healthz, /metrics, ...) + --service-cert.cert-class string Identifier used to differentiate responsible controllers for entries of controller service-cert + --service-cert.cert-target-class string Identifier used to differentiate responsible dns controllers for target entries of controller service-cert + --service-cert.default.pool.resync-period duration Period for resynchronization for pool default of controller service-cert + --service-cert.default.pool.size int Worker pool size for pool default of controller service-cert + --service-cert.pool.resync-period duration Period for resynchronization of controller service-cert + --service-cert.pool.size int Worker pool size of controller service-cert + --service-cert.target-name-prefix string name prefix in target namespace for cross cluster generation of controller service-cert + --service-cert.target-namespace string target namespace for cross cluster generation of controller service-cert + --service-cert.targets.pool.size int Worker pool size for pool targets of controller service-cert + --source string source cluster to watch for ingresses and services + --source.disable-deploy-crds disable deployment of required crds for cluster source + --source.id string id for cluster source + --source.migration-ids string migration id for cluster source + --target string target cluster for certificates + --target-name-prefix string name prefix in target namespace for cross cluster generation + --target-namespace string target namespace for cross cluster generation + --target.disable-deploy-crds disable deployment of required crds for cluster target + --target.id string id for cluster target + --target.migration-ids string migration id for cluster target + --targets.pool.size int Worker pool size for pool targets + --targetsources.pool.size int Worker pool size for pool targetsources + --use-dnsrecords if true, DNSRecords (using Gardener Provider extensions) are created instead of DNSEntries + -v, --version version for cert-controller-manager + --virtualservices.pool.size int Worker pool size for pool virtualservices + --watch-gateways-crds.default.pool.size int Worker pool size for pool default of controller watch-gateways-crds + --watch-gateways-crds.pool.size int Worker pool size of controller watch-gateways-crds ``` ## Renewal of Certificates @@ -1077,6 +1118,12 @@ Besides the default Go metrics, the following cert-management specific metrics a | cert_management_revoked_certificates | - | Number of certificate objects with revoked certificate | | cert_management_secrets | classification | Number of certificate secrets per classification (only updated on startup and every 24h on GC of secrets). Currently there are three classifications: `total` = total number of certificate secrets on the source cluster, `revoked` = number of revoked certificate secrets, `backup`= number of backups of certificate secrets (every certificate has a backup secret in the `kube-system` namespace to allow revocation even if it is not used anymore) | +## Using DNSRecords + +With the command line option `--use-dnsrecords`, the cert-controller-manager creates `DNSRecords` resources instead of +`DNSEntries`. In this case, the `Certificate` or source objects need two additional annotations: +- `cert.gardener.cloud/dnsrecord-provider-type` to fill the `.spec.type` field of `DNSRecords` +- `cert.gardener.cloud/dnsrecord-secret-ref` to fill the `.spec.secretRef`. The value is either the name of the secret in the same namespace as the certificate or in the format `/`. ## Troubleshooting diff --git a/examples/30-cert-simple.yaml b/examples/30-cert-simple.yaml index 448c0af7..58da2fb7 100644 --- a/examples/30-cert-simple.yaml +++ b/examples/30-cert-simple.yaml @@ -8,6 +8,9 @@ metadata: annotations: # class annotation only needed if cert-controller-manager is started with --cert-class=myclass #cert.gardener.cloud/class: myclass + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret name: cert-simple namespace: default spec: diff --git a/examples/40-gateway-gateway-api.yaml b/examples/40-gateway-gateway-api.yaml index f342027c..21d6ff3c 100644 --- a/examples/40-gateway-gateway-api.yaml +++ b/examples/40-gateway-gateway-api.yaml @@ -11,6 +11,9 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret name: my-gateway namespace: default spec: diff --git a/examples/40-ingress-echoheaders.yaml b/examples/40-ingress-echoheaders.yaml index 8ab3a2fd..44616677 100644 --- a/examples/40-ingress-echoheaders.yaml +++ b/examples/40-ingress-echoheaders.yaml @@ -18,6 +18,9 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret spec: tls: - hosts: diff --git a/examples/40-service-loadbalancer.yaml b/examples/40-service-loadbalancer.yaml index 47fef3d4..83df959a 100644 --- a/examples/40-service-loadbalancer.yaml +++ b/examples/40-service-loadbalancer.yaml @@ -18,6 +18,10 @@ metadata: #cert.gardener.cloud/preferred-chain: "chain name" # optional to specify preferred-chain (value is the Subject Common Name of the root issuer) #cert.gardener.cloud/private-key-algorithm: ECDSA # optional to specify algorithm for private key, allowed values are 'RSA' or 'ECDSA' #cert.gardener.cloud/private-key-size: "384" # optional to specify size of private key, allowed values for RSA are "2048", "3072", "4096" and for ECDSA "256" and "384" + # annotations needed when using DNSRecords + #cert.gardener.cloud/dnsrecord-provider-type: aws-route53 + #cert.gardener.cloud/dnsrecord-secret-ref: myns/mysecret + name: test-service namespace: default spec: diff --git a/pkg/cert/source/controller.go b/pkg/cert/source/controller.go index 8f711271..173e955d 100644 --- a/pkg/cert/source/controller.go +++ b/pkg/cert/source/controller.go @@ -45,6 +45,11 @@ const ( // AnnotPreferredChain is the annotation for the certificate preferred chain AnnotPreferredChain = "cert.gardener.cloud/preferred-chain" + // AnnotDNSRecordProviderType is the annotation for providing the provider type for DNS records. + AnnotDNSRecordProviderType = api.GroupName + "/dnsrecord-provider-type" + // AnnotDNSRecordSecretRef is the annotation for providing the secret ref for DNS records. + AnnotDNSRecordSecretRef = api.GroupName + "/dnsrecord-secret-ref" + // AnnotPrivateKeyAlgorithm is the annotation key to set the PrivateKeyAlgorithm for a Certificate. // If PrivateKeyAlgorithm is specified and `size` is not provided, // key size of 256 will be used for `ECDSA` key algorithm and diff --git a/pkg/cert/source/defaults.go b/pkg/cert/source/defaults.go index d561867a..85d5f9fa 100644 --- a/pkg/cert/source/defaults.go +++ b/pkg/cert/source/defaults.go @@ -206,6 +206,7 @@ func (s *DefaultCertSource) GetCertsInfo(logger logger.LogContext, objData resou PreferredChain: preferredChain, PrivateKeyAlgorithm: algorithm, PrivateKeySize: keySize, + Annotations: CopyDNSRecordsAnnotations(objData), } return info, nil } diff --git a/pkg/cert/source/interface.go b/pkg/cert/source/interface.go index e1cb802b..7d9a9c89 100644 --- a/pkg/cert/source/interface.go +++ b/pkg/cert/source/interface.go @@ -29,6 +29,7 @@ type CertInfo struct { PreferredChain string PrivateKeyAlgorithm string PrivateKeySize int + Annotations map[string]string } // CertsInfo contains a map of CertInfo. diff --git a/pkg/cert/source/reconciler.go b/pkg/cert/source/reconciler.go index b2b452b8..1c2fbe09 100644 --- a/pkg/cert/source/reconciler.go +++ b/pkg/cert/source/reconciler.go @@ -360,6 +360,10 @@ func (r *sourceReconciler) createEntryFor(logger logger.LogContext, obj resource cert.Spec.PrivateKey = createPrivateKey(info.PrivateKeyAlgorithm, info.PrivateKeySize) + for key, value := range info.Annotations { + resources.SetAnnotation(cert, key, value) + } + e, _ := r.SlaveResoures()[0].Wrap(cert) err := r.Slaves().CreateSlave(obj, e) @@ -468,6 +472,12 @@ func (r *sourceReconciler) updateEntry(logger logger.LogContext, info CertInfo, mod.Modify(true) } + for key, value := range info.Annotations { + if resources.SetAnnotation(o, key, value) { + mod.Modify(true) + } + } + if mod.IsModified() { logger.Infof("update certificate object %s", obj.ObjectName()) } diff --git a/pkg/cert/source/utils.go b/pkg/cert/source/utils.go index 4f799075..4ad54c7a 100644 --- a/pkg/cert/source/utils.go +++ b/pkg/cert/source/utils.go @@ -16,7 +16,7 @@ func requireFinalizer(src resources.Object, cluster resources.Cluster) bool { return src.GetCluster() != cluster } -// ExtractSecretLabels extracts label key value map from annotation +// ExtractSecretLabels extracts label key value map from annotation. func ExtractSecretLabels(objData resources.ObjectData) (secretLabels map[string]string) { if labels, ok := resources.GetAnnotation(objData, AnnotCertSecretLabels); ok { secretLabels = map[string]string{} @@ -30,3 +30,16 @@ func ExtractSecretLabels(objData resources.ObjectData) (secretLabels map[string] } return } + +// CopyDNSRecordsAnnotations extracts DNSRecord related annotations. +func CopyDNSRecordsAnnotations(data resources.ObjectData) (annotations map[string]string) { + for _, annotKey := range []string{AnnotDNSRecordProviderType, AnnotDNSRecordSecretRef} { + if value := data.GetAnnotations()[annotKey]; value != "" { + if annotations == nil { + annotations = map[string]string{} + } + annotations[annotKey] = value + } + } + return +} diff --git a/pkg/controller/issuer/certificate/reconciler.go b/pkg/controller/issuer/certificate/reconciler.go index 613e6286..3770bc26 100644 --- a/pkg/controller/issuer/certificate/reconciler.go +++ b/pkg/controller/issuer/certificate/reconciler.go @@ -56,10 +56,6 @@ const ( AnnotationRevoked = api.GroupName + "/revoked" // AnnotationRequestedAt is the annotation for storing the timestamp when the certificate was requested AnnotationRequestedAt = api.GroupName + "/requestedAt" - // AnnotationDNSRecordProviderType is the annotation for providing the provider type for DNS records. - AnnotationDNSRecordProviderType = api.GroupName + "/dnsrecord-provider-type" - // AnnotationDNSRecordSecretRef is the annotation for providing the secret ref for DNS records. - AnnotationDNSRecordSecretRef = api.GroupName + "/dnsrecord-secret-ref" ) type backoffMode int @@ -1321,13 +1317,13 @@ func (r *certReconciler) cleanupOrphanOutdatedCertificateSecrets() { } func createDNSRecordSettings(cert *api.Certificate) (*legobridge.DNSRecordSettings, error) { - typ := cert.Annotations[AnnotationDNSRecordProviderType] + typ := cert.Annotations[source.AnnotDNSRecordProviderType] if typ == "" { - return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", AnnotationDNSRecordProviderType) + return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", source.AnnotDNSRecordProviderType) } - ref := cert.Annotations[AnnotationDNSRecordSecretRef] + ref := cert.Annotations[source.AnnotDNSRecordSecretRef] if ref == "" { - return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", AnnotationDNSRecordSecretRef) + return nil, fmt.Errorf("missing annotation %s for creating DNSRecord", source.AnnotDNSRecordSecretRef) } parts := strings.SplitN(ref, "/", 2) var secretRef corev1.SecretReference diff --git a/pkg/controller/source/gateways/gatewayapi/handler_test.go b/pkg/controller/source/gateways/gatewayapi/handler_test.go index edd814f5..1a16cf91 100644 --- a/pkg/controller/source/gateways/gatewayapi/handler_test.go +++ b/pkg/controller/source/gateways/gatewayapi/handler_test.go @@ -282,14 +282,16 @@ var _ = Describe("Kubernetes Networking Gateway Handler", func() { Namespace: "test", Name: "g1", Annotations: map[string]string{ - ctrlsource.AnnotationPurposeKey: ctrlsource.AnnotationPurposeValueManaged, - source.AnnotPreferredChain: "chain2", - source.AnnotCommonName: "a.example.com", - source.AnnotCertDNSNames: "c.example.com,d.example.com", - source.AnnotIssuer: "test-issuer", - source.AnnotPrivateKeyAlgorithm: "ECDSA", - source.AnnotPrivateKeySize: "384", - source.AnnotCertSecretLabels: "a=b, c=bar42", + ctrlsource.AnnotationPurposeKey: ctrlsource.AnnotationPurposeValueManaged, + source.AnnotPreferredChain: "chain2", + source.AnnotCommonName: "a.example.com", + source.AnnotCertDNSNames: "c.example.com,d.example.com", + source.AnnotIssuer: "test-issuer", + source.AnnotPrivateKeyAlgorithm: "ECDSA", + source.AnnotPrivateKeySize: "384", + source.AnnotCertSecretLabels: "a=b, c=bar42", + source.AnnotDNSRecordProviderType: "dummy-type", + source.AnnotDNSRecordSecretRef: "dummy", }, }, Spec: gatewayapisv1.GatewaySpec{ @@ -311,6 +313,10 @@ var _ = Describe("Kubernetes Networking Gateway Handler", func() { info.PrivateKeySize = 384 info.IssuerName = ptr.To("test-issuer") info.SecretLabels = map[string]string{"a": "b", "c": "bar42"} + info.Annotations = map[string]string{ + source.AnnotDNSRecordProviderType: "dummy-type", + source.AnnotDNSRecordSecretRef: "dummy", + } return info })))) }) diff --git a/pkg/controller/source/helper.go b/pkg/controller/source/helper.go index 5202074f..b2c7f7ff 100644 --- a/pkg/controller/source/helper.go +++ b/pkg/controller/source/helper.go @@ -77,6 +77,7 @@ func GetCertsInfoByCollector(logger logger.LogContext, objData resources.ObjectD if ok { issuer = &annotatedIssuer } + for _, tls := range tlsDataArray { if tls.SecretName == "" { err = fmt.Errorf("tls entry for hosts %s has no secretName", source.DomainsString(tls.Hosts)) @@ -102,6 +103,7 @@ func GetCertsInfoByCollector(logger logger.LogContext, objData resources.ObjectD PreferredChain: preferredChain, PrivateKeyAlgorithm: algorithm, PrivateKeySize: keySize, + Annotations: source.CopyDNSRecordsAnnotations(objData), } } return info, err From 8cb3af8f2710d7b0a9f29c1848cb2c35ebed7897 Mon Sep 17 00:00:00 2001 From: Martin Weindel Date: Tue, 4 Jun 2024 16:24:50 +0200 Subject: [PATCH 3/3] fix typo --- charts/cert-management/templates/clusterrole.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/cert-management/templates/clusterrole.yaml b/charts/cert-management/templates/clusterrole.yaml index db5afb1a..abd6a7ad 100644 --- a/charts/cert-management/templates/clusterrole.yaml +++ b/charts/cert-management/templates/clusterrole.yaml @@ -95,7 +95,7 @@ rules: - update - create - watch -{{- if .Values.configuration.useDnsRecords }} +{{- if .Values.configuration.useDnsrecords }} - apiGroups: - extensions.gardener.cloud resources: