From 686854829dfdec98ed4aa95f59da4820e2deedd5 Mon Sep 17 00:00:00 2001 From: mattmoor-sockpuppet Date: Wed, 30 Oct 2019 07:26:13 -0700 Subject: [PATCH] Auto-update dependencies (#125) Produced via: `dep ensure -update knative.dev/test-infra knative.dev/pkg` /assign mattmoor --- Gopkg.lock | 6 +- vendor/knative.dev/pkg/Gopkg.lock | 1 + .../pkg/injection/sharedmain/main.go | 33 +++++- .../webhook-apicoverage/webhook/webhook.go | 3 +- .../{ => certificates/resources}/certs.go | 4 +- .../webhook/certificates/resources/secret.go | 54 +++++++++ .../pkg/webhook/testing/testing.go | 111 ++++++++++++++++++ vendor/knative.dev/pkg/webhook/webhook.go | 57 ++++----- 8 files changed, 230 insertions(+), 39 deletions(-) rename vendor/knative.dev/pkg/webhook/{ => certificates/resources}/certs.go (99%) create mode 100644 vendor/knative.dev/pkg/webhook/certificates/resources/secret.go create mode 100644 vendor/knative.dev/pkg/webhook/testing/testing.go diff --git a/Gopkg.lock b/Gopkg.lock index 90963218..fbdbf9e2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -933,7 +933,7 @@ [[projects]] branch = "master" - digest = "1:b1b13cac811c873045205cd087aa9d8ce98fc49370e1eac4c4a5838bc9acef31" + digest = "1:2cc284a39bc41da614158a089ed2e976cd5461a93ede77f52263c1f3370995c2" name = "knative.dev/pkg" packages = [ "apis", @@ -952,7 +952,7 @@ "metrics/metricskey", ] pruneopts = "T" - revision = "349698bdf82bc8d8d406ce9ffa183abeafe6fb02" + revision = "3732de5802012193835c9fe65436b761ed3fecea" [[projects]] branch = "master" @@ -963,7 +963,7 @@ "tools/dep-collector", ] pruneopts = "UT" - revision = "bb87d561aa59603ec585dbf145e8d9ced5b19d59" + revision = "34a629e61afcc53b94725894cdc4caf70b536ee1" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" diff --git a/vendor/knative.dev/pkg/Gopkg.lock b/vendor/knative.dev/pkg/Gopkg.lock index d917f79e..bf513fbc 100644 --- a/vendor/knative.dev/pkg/Gopkg.lock +++ b/vendor/knative.dev/pkg/Gopkg.lock @@ -1382,6 +1382,7 @@ "k8s.io/client-go/kubernetes/fake", "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/kubernetes/typed/core/v1", + "k8s.io/client-go/listers/core/v1", "k8s.io/client-go/plugin/pkg/client/auth/gcp", "k8s.io/client-go/rest", "k8s.io/client-go/testing", diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go index 73c154c8..b418db18 100644 --- a/vendor/knative.dev/pkg/injection/sharedmain/main.go +++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go @@ -44,6 +44,8 @@ import ( "knative.dev/pkg/profiling" "knative.dev/pkg/signals" "knative.dev/pkg/system" + "knative.dev/pkg/version" + "knative.dev/pkg/webhook" ) // GetConfig returns a rest.Config to be used for kubernetes client creation. @@ -138,13 +140,25 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto defer flush(logger) ctx = logging.WithLogger(ctx, logger) + kc := kubeclient.Get(ctx) + if err := version.CheckMinimumVersion(kc.Discovery()); err != nil { + logger.Fatalw("Version check failed", zap.Error(err)) + } + // TODO(mattmoor): This should itself take a context and be injection-based. - cmw := configmap.NewInformedWatcher(kubeclient.Get(ctx), system.Namespace()) + cmw := configmap.NewInformedWatcher(kc, system.Namespace()) // Based on the reconcilers we have linked, build up the set of controllers to run. controllers := make([]*controller.Impl, 0, len(ctors)) + webhooks := make([]webhook.AdmissionController, 0) for _, cf := range ctors { - controllers = append(controllers, cf(ctx, cmw)) + ctrl := cf(ctx, cmw) + controllers = append(controllers, ctrl) + + // Build a list of any reconcilers that implement webhook.AdmissionController + if ac, ok := ctrl.Reconciler.(webhook.AdmissionController); ok { + webhooks = append(webhooks, ac) + } } profilingHandler := profiling.NewHandler(logger, false) @@ -176,6 +190,21 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto eg, egCtx := errgroup.WithContext(ctx) eg.Go(profilingServer.ListenAndServe) + // If we have one or more admission controllers, then start the webhook + // and pass them in. + if len(webhooks) > 0 { + // Register webhook metrics + webhook.RegisterMetrics() + + wh, err := webhook.New(ctx, webhooks) + if err != nil { + logger.Fatalw("Failed to create admission controller", zap.Error(err)) + } + eg.Go(func() error { + return wh.Run(ctx.Done()) + }) + } + // This will block until either a signal arrives or one of the grouped functions // returns an error. <-egCtx.Done() diff --git a/vendor/knative.dev/pkg/test/webhook-apicoverage/webhook/webhook.go b/vendor/knative.dev/pkg/test/webhook-apicoverage/webhook/webhook.go index 80e8edd2..ccfeba87 100644 --- a/vendor/knative.dev/pkg/test/webhook-apicoverage/webhook/webhook.go +++ b/vendor/knative.dev/pkg/test/webhook-apicoverage/webhook/webhook.go @@ -37,6 +37,7 @@ import ( "knative.dev/pkg/configmap" "knative.dev/pkg/logging" "knative.dev/pkg/webhook" + certresources "knative.dev/pkg/webhook/certificates/resources" ) var ( @@ -84,7 +85,7 @@ type APICoverageWebhook struct { } func (acw *APICoverageWebhook) generateServerConfig() (*tls.Config, error) { - serverKey, serverCert, caCert, err := webhook.CreateCerts(context.Background(), acw.ServiceName, acw.Namespace) + serverKey, serverCert, caCert, err := certresources.CreateCerts(context.Background(), acw.ServiceName, acw.Namespace) if err != nil { return nil, fmt.Errorf("Error creating webhook certificates: %v", err) } diff --git a/vendor/knative.dev/pkg/webhook/certs.go b/vendor/knative.dev/pkg/webhook/certificates/resources/certs.go similarity index 99% rename from vendor/knative.dev/pkg/webhook/certs.go rename to vendor/knative.dev/pkg/webhook/certificates/resources/certs.go index 1a034839..aaa0b78a 100644 --- a/vendor/knative.dev/pkg/webhook/certs.go +++ b/vendor/knative.dev/pkg/webhook/certificates/resources/certs.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +Copyright 2019 The Knative Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package webhook +package resources import ( "context" diff --git a/vendor/knative.dev/pkg/webhook/certificates/resources/secret.go b/vendor/knative.dev/pkg/webhook/certificates/resources/secret.go new file mode 100644 index 00000000..c5494e2e --- /dev/null +++ b/vendor/knative.dev/pkg/webhook/certificates/resources/secret.go @@ -0,0 +1,54 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // ServerKey is the name of the key associated with the secret's private key. + ServerKey = "server-key.pem" + // ServerCert is the name of the key associated with the secret's public key. + ServerCert = "server-cert.pem" + // CACert is the name of the key associated with the certificate of the CA for + // the keypair. + CACert = "ca-cert.pem" +) + +// MakeSecret synthesizes a Kubernetes Secret object with the keys specified by +// ServerKey, ServerCert, and CACert populated with a fresh certificate. +func MakeSecret(ctx context.Context, name, namespace, serviceName string) (*corev1.Secret, error) { + serverKey, serverCert, caCert, err := CreateCerts(ctx, serviceName, namespace) + if err != nil { + return nil, err + } + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: map[string][]byte{ + ServerKey: serverKey, + ServerCert: serverCert, + CACert: caCert, + }, + }, nil +} diff --git a/vendor/knative.dev/pkg/webhook/testing/testing.go b/vendor/knative.dev/pkg/webhook/testing/testing.go new file mode 100644 index 00000000..7e3b3175 --- /dev/null +++ b/vendor/knative.dev/pkg/webhook/testing/testing.go @@ -0,0 +1,111 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import ( + "encoding/json" + "sort" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/mattbaird/jsonpatch" + admissionv1beta1 "k8s.io/api/admission/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/system" + + // Makes system.Namespace work in tests. + _ "knative.dev/pkg/system/testing" + + . "knative.dev/pkg/testing" +) + +// CreateResource creates a testing.Resource with the given name in the system namespace. +func CreateResource(name string) *Resource { + return &Resource{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: system.Namespace(), + Name: name, + }, + Spec: ResourceSpec{ + FieldWithValidation: "magic value", + }, + } +} + +// ExpectAllowed checks that a given admission response allows the initiating request through. +func ExpectAllowed(t *testing.T, resp *admissionv1beta1.AdmissionResponse) { + t.Helper() + if !resp.Allowed { + t.Errorf("Expected allowed, but failed with %+v", resp.Result) + } +} + +// ExpectFailsWith checks that a given admission response disallows the initiating request +// through and contains the provided string in its error message. +func ExpectFailsWith(t *testing.T, resp *admissionv1beta1.AdmissionResponse, contains string) { + t.Helper() + if resp.Allowed { + t.Error("Expected denial, got allowed") + return + } + if !strings.Contains(resp.Result.Message, contains) { + t.Errorf("Expected failure containing %q got %q", contains, resp.Result.Message) + } +} + +// ExpectPatches checks that the provided serialized bytes consist of an expected +// collection of patches. This is used to verify the mutations made in a mutating +// admission webhook's response. +func ExpectPatches(t *testing.T, a []byte, e []jsonpatch.JsonPatchOperation) { + t.Helper() + var got []jsonpatch.JsonPatchOperation + + err := json.Unmarshal(a, &got) + if err != nil { + t.Errorf("Failed to unmarshal patches: %s", err) + return + } + + // Give the patch a deterministic ordering. + // Technically this can change the meaning, but the ordering is otherwise unstable + // and difficult to test. + sort.Slice(e, func(i, j int) bool { + lhs, rhs := e[i], e[j] + if lhs.Operation != rhs.Operation { + return lhs.Operation < rhs.Operation + } + return lhs.Path < rhs.Path + }) + sort.Slice(got, func(i, j int) bool { + lhs, rhs := got[i], got[j] + if lhs.Operation != rhs.Operation { + return lhs.Operation < rhs.Operation + } + return lhs.Path < rhs.Path + }) + + // Even though diff is useful, seeing the whole objects + // one under another helps a lot. + t.Logf("Got Patches: %#v", got) + t.Logf("Want Patches: %#v", e) + if diff := cmp.Diff(e, got, cmpopts.EquateEmpty()); diff != "" { + t.Logf("diff Patches: %v", diff) + t.Errorf("ExpectPatches (-want, +got) = %s", diff) + } +} diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go index 66ea54ae..8cf68673 100644 --- a/vendor/knative.dev/pkg/webhook/webhook.go +++ b/vendor/knative.dev/pkg/webhook/webhook.go @@ -27,24 +27,20 @@ import ( // Injection stuff kubeclient "knative.dev/pkg/client/injection/kube/client" + secretinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/secret" "go.uber.org/zap" "golang.org/x/sync/errgroup" "knative.dev/pkg/logging" "knative.dev/pkg/logging/logkey" "knative.dev/pkg/system" + certresources "knative.dev/pkg/webhook/certificates/resources" admissionv1beta1 "k8s.io/api/admission/v1beta1" - corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" -) - -const ( - secretServerKey = "server-key.pem" - secretServerCert = "server-cert.pem" - secretCACert = "ca-cert.pem" + corelisters "k8s.io/client-go/listers/core/v1" ) var ( @@ -99,6 +95,7 @@ type Webhook struct { Options Options Logger *zap.SugaredLogger admissionControllers map[string]AdmissionController + secretlister corelisters.SecretLister } // New constructs a Webhook @@ -108,6 +105,7 @@ func New( ) (*Webhook, error) { client := kubeclient.Get(ctx) + secretInformer := secretinformer.Get(ctx) opts := GetOptions(ctx) if opts == nil { return nil, errors.New("context must have Options specified") @@ -133,6 +131,7 @@ func New( return &Webhook{ Client: client, Options: *opts, + secretlister: secretInformer.Lister(), admissionControllers: acs, Logger: logger, }, nil @@ -145,7 +144,7 @@ func (ac *Webhook) Run(stop <-chan struct{}) error { // TODO(mattmoor): Separate out the certificate creation process and use listers // to fetch this from the secret below. - serverKey, serverCert, caCert, err := getOrGenerateKeyCertsFromSecret(ctx, ac.Client, &ac.Options) + _, _, caCert, err := getOrGenerateKeyCertsFromSecret(ctx, ac.Client, &ac.Options) if err != nil { return err } @@ -155,6 +154,19 @@ func (ac *Webhook) Run(stop <-chan struct{}) error { Addr: fmt.Sprintf(":%v", ac.Options.Port), TLSConfig: &tls.Config{ GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + secret, err := ac.secretlister.Secrets(system.Namespace()).Get(ac.Options.SecretName) + if err != nil { + return nil, err + } + + serverKey, ok := secret.Data[certresources.ServerKey] + if !ok { + return nil, errors.New("server key missing") + } + serverCert, ok := secret.Data[certresources.ServerCert] + if !ok { + return nil, errors.New("server cert missing") + } cert, err := tls.X509KeyPair(serverCert, serverKey) if err != nil { return nil, err @@ -205,7 +217,7 @@ func (ac *Webhook) Run(stop <-chan struct{}) error { case <-stop: return server.Close() case <-ctx.Done(): - return fmt.Errorf("webhook server bootstrap failed %v", err) + return fmt.Errorf("webhook server bootstrap failed %v", ctx.Err()) } } @@ -275,7 +287,8 @@ func getOrGenerateKeyCertsFromSecret(ctx context.Context, client kubernetes.Inte return nil, nil, nil, err } logger.Info("Did not find existing secret, creating one") - newSecret, err := generateSecret(ctx, options) + newSecret, err := certresources.MakeSecret( + ctx, options.SecretName, system.Namespace(), options.ServiceName) if err != nil { return nil, nil, nil, err } @@ -293,13 +306,13 @@ func getOrGenerateKeyCertsFromSecret(ctx context.Context, client kubernetes.Inte } var ok bool - if serverKey, ok = secret.Data[secretServerKey]; !ok { + if serverKey, ok = secret.Data[certresources.ServerKey]; !ok { return nil, nil, nil, errors.New("server key missing") } - if serverCert, ok = secret.Data[secretServerCert]; !ok { + if serverCert, ok = secret.Data[certresources.ServerCert]; !ok { return nil, nil, nil, errors.New("server cert missing") } - if caCert, ok = secret.Data[secretCACert]; !ok { + if caCert, ok = secret.Data[certresources.CACert]; !ok { return nil, nil, nil, errors.New("ca cert missing") } return serverKey, serverCert, caCert, nil @@ -312,21 +325,3 @@ func makeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.Admis Allowed: false, } } - -func generateSecret(ctx context.Context, options *Options) (*corev1.Secret, error) { - serverKey, serverCert, caCert, err := CreateCerts(ctx, options.ServiceName, system.Namespace()) - if err != nil { - return nil, err - } - return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: options.SecretName, - Namespace: system.Namespace(), - }, - Data: map[string][]byte{ - secretServerKey: serverKey, - secretServerCert: serverCert, - secretCACert: caCert, - }, - }, nil -}