knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/certificates/certificates.go (about) 1 /* 2 Copyright 2019 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package certificates 18 19 import ( 20 "context" 21 "crypto/tls" 22 "crypto/x509" 23 "time" 24 25 "go.uber.org/zap" 26 apierrors "k8s.io/apimachinery/pkg/api/errors" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/types" 29 "k8s.io/client-go/kubernetes" 30 corelisters "k8s.io/client-go/listers/core/v1" 31 "knative.dev/pkg/controller" 32 "knative.dev/pkg/logging" 33 pkgreconciler "knative.dev/pkg/reconciler" 34 certresources "knative.dev/pkg/webhook/certificates/resources" 35 ) 36 37 const ( 38 // Time used for updating a certificate before it expires. 39 oneDay = 24 * time.Hour 40 ) 41 42 type reconciler struct { 43 pkgreconciler.LeaderAwareFuncs 44 45 client kubernetes.Interface 46 secretlister corelisters.SecretLister 47 key types.NamespacedName 48 serviceName string 49 } 50 51 var ( 52 _ controller.Reconciler = (*reconciler)(nil) 53 _ pkgreconciler.LeaderAware = (*reconciler)(nil) 54 ) 55 56 // Reconcile implements controller.Reconciler 57 func (r *reconciler) Reconcile(ctx context.Context, key string) error { 58 if r.IsLeaderFor(r.key) { 59 // only reconciler the certificate when we are leader. 60 return r.reconcileCertificate(ctx) 61 } 62 return controller.NewSkipKey(key) 63 } 64 65 func (r *reconciler) reconcileCertificate(ctx context.Context) error { 66 logger := logging.FromContext(ctx) 67 68 secret, err := r.secretlister.Secrets(r.key.Namespace).Get(r.key.Name) 69 if apierrors.IsNotFound(err) { 70 // The secret should be created explicitly by a higher-level system 71 // that's responsible for install/updates. We simply populate the 72 // secret information. 73 return nil 74 } else if err != nil { 75 logger.Errorf("Error accessing certificate secret %q: %v", r.key.Name, err) 76 return err 77 } 78 79 if _, haskey := secret.Data[certresources.ServerKey]; !haskey { 80 logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.ServerKey) 81 } else if _, haskey := secret.Data[certresources.ServerCert]; !haskey { 82 logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.ServerCert) 83 } else if _, haskey := secret.Data[certresources.CACert]; !haskey { 84 logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.CACert) 85 } else { 86 // Check the expiration date of the certificate to see if it needs to be updated 87 cert, err := tls.X509KeyPair(secret.Data[certresources.ServerCert], secret.Data[certresources.ServerKey]) 88 if err != nil { 89 logger.Warnw("Error creating pem from certificate and key", zap.Error(err)) 90 } else { 91 certData, err := x509.ParseCertificate(cert.Certificate[0]) 92 if err != nil { 93 logger.Errorw("Error parsing certificate", zap.Error(err)) 94 } else if time.Now().Add(oneDay).Before(certData.NotAfter) { 95 return nil 96 } 97 } 98 } 99 // Don't modify the informer copy. 100 secret = secret.DeepCopy() 101 102 // One of the secret's keys is missing, so synthesize a new one and update the secret. 103 newSecret, err := certresources.MakeSecret(ctx, r.key.Name, r.key.Namespace, r.serviceName) 104 if err != nil { 105 return err 106 } 107 secret.Data = newSecret.Data 108 _, err = r.client.CoreV1().Secrets(secret.Namespace).Update(ctx, secret, metav1.UpdateOptions{}) 109 return err 110 }