istio.io/istio@v0.0.0-20240520182934-d79c90f27776/security/pkg/k8s/configutil.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 k8s 16 17 import ( 18 "fmt" 19 20 v1 "k8s.io/api/core/v1" 21 "k8s.io/apimachinery/pkg/api/errors" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 24 "istio.io/istio/pkg/config/constants" 25 "istio.io/istio/pkg/kube/kclient" 26 "istio.io/istio/pkg/log" 27 ) 28 29 // InsertDataToConfigMap inserts a data to a configmap in a namespace. 30 // client: the k8s client interface. 31 // lister: the configmap lister. 32 // meta: the metadata of configmap. 33 // caBundle: ca cert data bytes. 34 func InsertDataToConfigMap(client kclient.Client[*v1.ConfigMap], meta metav1.ObjectMeta, caBundle []byte) error { 35 configmap := client.Get(meta.Name, meta.Namespace) 36 if configmap == nil { 37 // Create a new ConfigMap. 38 configmap = &v1.ConfigMap{ 39 ObjectMeta: meta, 40 Data: map[string]string{ 41 constants.CACertNamespaceConfigMapDataName: string(caBundle), 42 }, 43 } 44 if _, err := client.Create(configmap); err != nil { 45 // Namespace may be deleted between now... and our previous check. Just skip this, we cannot create into deleted ns 46 // And don't retry a create if the namespace is terminating 47 if errors.IsAlreadyExists(err) || errors.HasStatusCause(err, v1.NamespaceTerminatingCause) { 48 return nil 49 } 50 if errors.IsForbidden(err) { 51 log.Infof("skip writing ConfigMap %v/%v as we do not have permissions to do so", meta.Namespace, meta.Name) 52 return nil 53 } 54 return fmt.Errorf("error when creating configmap %v: %v", meta.Name, err) 55 } 56 } else { 57 // Otherwise, update the config map if changes are required 58 err := updateDataInConfigMap(client, configmap, caBundle) 59 if err != nil { 60 return err 61 } 62 } 63 return nil 64 } 65 66 // insertData merges a configmap with a map, and returns true if any changes were made 67 func insertData(cm *v1.ConfigMap, data map[string]string) bool { 68 if cm.Data == nil { 69 cm.Data = data 70 return true 71 } 72 needsUpdate := false 73 for k, v := range data { 74 if cm.Data[k] != v { 75 needsUpdate = true 76 } 77 cm.Data[k] = v 78 } 79 return needsUpdate 80 } 81 82 func updateDataInConfigMap(c kclient.Client[*v1.ConfigMap], cm *v1.ConfigMap, caBundle []byte) error { 83 if cm == nil { 84 return fmt.Errorf("cannot update nil configmap") 85 } 86 newCm := cm.DeepCopy() 87 data := map[string]string{ 88 constants.CACertNamespaceConfigMapDataName: string(caBundle), 89 } 90 if needsUpdate := insertData(newCm, data); !needsUpdate { 91 return nil 92 } 93 if _, err := c.Update(newCm); err != nil { 94 return fmt.Errorf("error when updating configmap %v: %v", cm.Name, err) 95 } 96 return nil 97 }