...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod/utils_linux.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/util/staticpod

     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  }
   197  

View as plain text