k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/staticpod/utils_linux.go (about) 1 //go:build linux 2 // +build linux 3 4 /* 5 Copyright 2021 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package staticpod 21 22 import ( 23 "fmt" 24 "path/filepath" 25 26 "github.com/pkg/errors" 27 28 v1 "k8s.io/api/core/v1" 29 "k8s.io/utils/ptr" 30 31 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" 32 kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" 33 certphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs" 34 "k8s.io/kubernetes/cmd/kubeadm/app/util/users" 35 ) 36 37 type pathOwnerAndPermissionsUpdaterFunc func(path string, uid, gid int64, perms uint32) error 38 type pathOwnerUpdaterFunc func(path string, uid, gid int64) error 39 40 // RunComponentAsNonRoot updates the pod manifest and the hostVolume permissions to run as non root. 41 func RunComponentAsNonRoot(componentName string, pod *v1.Pod, usersAndGroups *users.UsersAndGroups, cfg *kubeadmapi.ClusterConfiguration) error { 42 switch componentName { 43 case kubeadmconstants.KubeAPIServer: 44 return runKubeAPIServerAsNonRoot( 45 pod, 46 usersAndGroups.Users.ID(kubeadmconstants.KubeAPIServerUserName), 47 usersAndGroups.Groups.ID(kubeadmconstants.KubeAPIServerUserName), 48 usersAndGroups.Groups.ID(kubeadmconstants.ServiceAccountKeyReadersGroupName), 49 users.UpdatePathOwnerAndPermissions, 50 cfg, 51 ) 52 case kubeadmconstants.KubeControllerManager: 53 return runKubeControllerManagerAsNonRoot( 54 pod, 55 usersAndGroups.Users.ID(kubeadmconstants.KubeControllerManagerUserName), 56 usersAndGroups.Groups.ID(kubeadmconstants.KubeControllerManagerUserName), 57 usersAndGroups.Groups.ID(kubeadmconstants.ServiceAccountKeyReadersGroupName), 58 users.UpdatePathOwnerAndPermissions, 59 cfg, 60 ) 61 case kubeadmconstants.KubeScheduler: 62 return runKubeSchedulerAsNonRoot( 63 pod, 64 usersAndGroups.Users.ID(kubeadmconstants.KubeSchedulerUserName), 65 usersAndGroups.Groups.ID(kubeadmconstants.KubeSchedulerUserName), 66 users.UpdatePathOwnerAndPermissions, 67 ) 68 case kubeadmconstants.Etcd: 69 return runEtcdAsNonRoot( 70 pod, 71 usersAndGroups.Users.ID(kubeadmconstants.EtcdUserName), 72 usersAndGroups.Groups.ID(kubeadmconstants.EtcdUserName), 73 users.UpdatePathOwnerAndPermissions, 74 users.UpdatePathOwner, 75 cfg, 76 ) 77 } 78 return errors.New(fmt.Sprintf("component name %q is not valid", componentName)) 79 } 80 81 // runKubeAPIServerAsNonRoot updates the pod manifest and the hostVolume permissions to run kube-apiserver as non root. 82 func runKubeAPIServerAsNonRoot(pod *v1.Pod, runAsUser, runAsGroup, supplementalGroup *int64, updatePathOwnerAndPermissions pathOwnerAndPermissionsUpdaterFunc, cfg *kubeadmapi.ClusterConfiguration) error { 83 saPublicKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPublicKeyName) 84 if err := updatePathOwnerAndPermissions(saPublicKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 85 return err 86 } 87 saPrivateKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName) 88 if err := updatePathOwnerAndPermissions(saPrivateKeyFile, 0, *supplementalGroup, 0640); err != nil { 89 return err 90 } 91 apiServerKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKeyName) 92 if err := updatePathOwnerAndPermissions(apiServerKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 93 return err 94 } 95 apiServerKubeletClientKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerKubeletClientKeyName) 96 if err := updatePathOwnerAndPermissions(apiServerKubeletClientKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 97 return err 98 } 99 frontProxyClientKeyName := filepath.Join(cfg.CertificatesDir, kubeadmconstants.FrontProxyClientKeyName) 100 if err := updatePathOwnerAndPermissions(frontProxyClientKeyName, *runAsUser, *runAsGroup, 0600); err != nil { 101 return err 102 } 103 if cfg.Etcd.External == nil { 104 apiServerEtcdClientKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.APIServerEtcdClientKeyName) 105 if err := updatePathOwnerAndPermissions(apiServerEtcdClientKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 106 return err 107 } 108 } 109 pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{ 110 Capabilities: &v1.Capabilities{ 111 // We drop all capabilities that are added by default. 112 Drop: []v1.Capability{"ALL"}, 113 // kube-apiserver binary has the file capability cap_net_bind_service applied to it. 114 // This means that we must add this capability when running as non-root even if the 115 // capability is not required. 116 Add: []v1.Capability{"NET_BIND_SERVICE"}, 117 }, 118 } 119 pod.Spec.SecurityContext.RunAsGroup = runAsGroup 120 pod.Spec.SecurityContext.RunAsUser = runAsUser 121 pod.Spec.SecurityContext.SupplementalGroups = []int64{*supplementalGroup} 122 return nil 123 } 124 125 // runKubeControllerManagerAsNonRoot updates the pod manifest and the hostVolume permissions to run kube-controller-manager as non root. 126 func runKubeControllerManagerAsNonRoot(pod *v1.Pod, runAsUser, runAsGroup, supplementalGroup *int64, updatePathOwnerAndPermissions pathOwnerAndPermissionsUpdaterFunc, cfg *kubeadmapi.ClusterConfiguration) error { 127 kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ControllerManagerKubeConfigFileName) 128 if err := updatePathOwnerAndPermissions(kubeconfigFile, *runAsUser, *runAsGroup, 0600); err != nil { 129 return err 130 } 131 saPrivateKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.ServiceAccountPrivateKeyName) 132 if err := updatePathOwnerAndPermissions(saPrivateKeyFile, 0, *supplementalGroup, 0640); err != nil { 133 return err 134 } 135 if res, _ := certphase.UsingExternalCA(cfg); !res { 136 caKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.CAKeyName) 137 err := updatePathOwnerAndPermissions(caKeyFile, *runAsUser, *runAsGroup, 0600) 138 if err != nil { 139 return err 140 } 141 } 142 pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{ 143 AllowPrivilegeEscalation: ptr.To(false), 144 Capabilities: &v1.Capabilities{ 145 // We drop all capabilities that are added by default. 146 Drop: []v1.Capability{"ALL"}, 147 }, 148 } 149 pod.Spec.SecurityContext.RunAsUser = runAsUser 150 pod.Spec.SecurityContext.RunAsGroup = runAsGroup 151 pod.Spec.SecurityContext.SupplementalGroups = []int64{*supplementalGroup} 152 return nil 153 } 154 155 // runKubeSchedulerAsNonRoot updates the pod manifest and the hostVolume permissions to run kube-scheduler as non root. 156 func runKubeSchedulerAsNonRoot(pod *v1.Pod, runAsUser, runAsGroup *int64, updatePathOwnerAndPermissions pathOwnerAndPermissionsUpdaterFunc) error { 157 kubeconfigFile := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.SchedulerKubeConfigFileName) 158 if err := updatePathOwnerAndPermissions(kubeconfigFile, *runAsUser, *runAsGroup, 0600); err != nil { 159 return err 160 } 161 pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{ 162 AllowPrivilegeEscalation: ptr.To(false), 163 // We drop all capabilities that are added by default. 164 Capabilities: &v1.Capabilities{ 165 Drop: []v1.Capability{"ALL"}, 166 }, 167 } 168 pod.Spec.SecurityContext.RunAsUser = runAsUser 169 pod.Spec.SecurityContext.RunAsGroup = runAsGroup 170 return nil 171 } 172 173 // runEtcdAsNonRoot updates the pod manifest and the hostVolume permissions to run etcd as non root. 174 func runEtcdAsNonRoot(pod *v1.Pod, runAsUser, runAsGroup *int64, updatePathOwnerAndPermissions pathOwnerAndPermissionsUpdaterFunc, updatePathOwner pathOwnerUpdaterFunc, cfg *kubeadmapi.ClusterConfiguration) error { 175 if err := updatePathOwner(cfg.Etcd.Local.DataDir, *runAsUser, *runAsGroup); err != nil { 176 return err 177 } 178 etcdServerKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdServerKeyName) 179 if err := updatePathOwnerAndPermissions(etcdServerKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 180 return err 181 } 182 etcdPeerKeyFile := filepath.Join(cfg.CertificatesDir, kubeadmconstants.EtcdPeerKeyName) 183 if err := updatePathOwnerAndPermissions(etcdPeerKeyFile, *runAsUser, *runAsGroup, 0600); err != nil { 184 return err 185 } 186 pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{ 187 AllowPrivilegeEscalation: ptr.To(false), 188 // We drop all capabilities that are added by default. 189 Capabilities: &v1.Capabilities{ 190 Drop: []v1.Capability{"ALL"}, 191 }, 192 } 193 pod.Spec.SecurityContext.RunAsUser = runAsUser 194 pod.Spec.SecurityContext.RunAsGroup = runAsGroup 195 return nil 196 }