istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/bootstrap/sidecarinjector.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bootstrap 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "path/filepath" 22 23 "k8s.io/apimachinery/pkg/api/errors" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 26 "istio.io/istio/pilot/pkg/features" 27 "istio.io/istio/pkg/env" 28 "istio.io/istio/pkg/kube/inject" 29 "istio.io/istio/pkg/log" 30 "istio.io/istio/pkg/webhooks" 31 ) 32 33 const ( 34 // Name of the webhook config in the config - no need to change it. 35 webhookName = "sidecar-injector.istio.io" 36 // defaultInjectorConfigMapName is the default name of the ConfigMap with the injection config 37 // The actual name can be different - use getInjectorConfigMapName 38 defaultInjectorConfigMapName = "istio-sidecar-injector" 39 ) 40 41 var injectionEnabled = env.Register("INJECT_ENABLED", true, "Enable mutating webhook handler.") 42 43 func (s *Server) initSidecarInjector(args *PilotArgs) (*inject.Webhook, error) { 44 // currently the constant: "./var/lib/istio/inject" 45 injectPath := args.InjectionOptions.InjectionDirectory 46 if injectPath == "" || !injectionEnabled.Get() { 47 log.Infof("Skipping sidecar injector, injection path is missing or disabled.") 48 return nil, nil 49 } 50 51 // If the injection config exists either locally or remotely, we will set up injection. 52 var watcher inject.Watcher 53 if _, err := os.Stat(filepath.Join(injectPath, "config")); !os.IsNotExist(err) { 54 configFile := filepath.Join(injectPath, "config") 55 valuesFile := filepath.Join(injectPath, "values") 56 watcher, err = inject.NewFileWatcher(configFile, valuesFile) 57 if err != nil { 58 return nil, err 59 } 60 } else if s.kubeClient != nil { 61 configMapName := getInjectorConfigMapName(args.Revision) 62 cms := s.kubeClient.Kube().CoreV1().ConfigMaps(args.Namespace) 63 if _, err := cms.Get(context.TODO(), configMapName, metav1.GetOptions{}); err != nil { 64 if errors.IsNotFound(err) { 65 log.Infof("Skipping sidecar injector, template not found") 66 return nil, nil 67 } 68 return nil, err 69 } 70 watcher = inject.NewConfigMapWatcher(s.kubeClient, args.Namespace, configMapName, "config", "values") 71 } else { 72 log.Infof("Skipping sidecar injector, template not found") 73 return nil, nil 74 } 75 76 log.Info("initializing sidecar injector") 77 78 parameters := inject.WebhookParameters{ 79 Watcher: watcher, 80 Env: s.environment, 81 Mux: s.httpsMux, 82 Revision: args.Revision, 83 MultiCluster: s.multiclusterController, 84 } 85 86 wh, err := inject.NewWebhook(parameters) 87 if err != nil { 88 return nil, fmt.Errorf("failed to create injection webhook: %v", err) 89 } 90 // Patch cert if a webhook config name is provided. 91 // This requires RBAC permissions - a low-priv Istiod should not attempt to patch but rely on 92 // operator or CI/CD 93 if features.InjectionWebhookConfigName != "" { 94 s.addStartFunc("injection patcher", func(stop <-chan struct{}) error { 95 // No leader election - different istiod revisions will patch their own cert. 96 // update webhook configuration by watching the cabundle 97 patcher, err := webhooks.NewWebhookCertPatcher(s.kubeClient, args.Revision, webhookName, s.istiodCertBundleWatcher) 98 if err != nil { 99 log.Errorf("failed to create webhook cert patcher: %v", err) 100 return nil 101 } 102 103 go patcher.Run(stop) 104 return nil 105 }) 106 } 107 108 s.addStartFunc("injection server", func(stop <-chan struct{}) error { 109 wh.Run(stop) 110 return nil 111 }) 112 return wh, nil 113 } 114 115 func getInjectorConfigMapName(revision string) string { 116 name := defaultInjectorConfigMapName 117 if revision == "" || revision == "default" { 118 return name 119 } 120 return name + "-" + revision 121 }