如上这个配置,可以看到 Pod 中所有容器内的进程都是已用户 uid=1000 和主组 gid=3000来运行的,而创建的任何文件的属组都是 groups=2000。通过这样的方法,可以达到让用户的进程不使用默认的 Root (uid=0,gid=0)权限的目的。
禁止容器以 Root 身份运行
如果 runAsNonRoot 字段配置为 true,kubelet 在启动容器时会进行检查,如果以 UID 为 0 运行,则禁止容器启动,该 Pod 的 STATUS 变为 CreateContainerConfigError,并生成 Warning 类型事件 Error: container has runAsNonRoot and image will run as root。只有当设置 runAsUser 或者镜像本身就不是以 Root 身份运行时,该 Pod 才能正常启动。
// verifyRunAsNonRoot verifies RunAsNonRoot.funcverifyRunAsNonRoot(pod*v1.Pod,container*v1.Container,uid*int64,usernamestring)error{effectiveSc:=securitycontext.DetermineEffectiveSecurityContext(pod,container)// If the option is not set, or if running as root is allowed, return nil.ifeffectiveSc==nil||effectiveSc.RunAsNonRoot==nil||!*effectiveSc.RunAsNonRoot{returnnil}ifeffectiveSc.RunAsUser!=nil{if*effectiveSc.RunAsUser==0{returnfmt.Errorf("container's runAsUser breaks non-root policy (pod: %q, container: %s)",format.Pod(pod),container.Name)}returnnil}switch{caseuid!=nil&&*uid==0:returnfmt.Errorf("container has runAsNonRoot and image will run as root (pod: %q, container: %s)",format.Pod(pod),container.Name)caseuid==nil&&len(username)>0:returnfmt.Errorf("container has runAsNonRoot and image has non-numeric user (%s), cannot verify user is non-root (pod: %q, container: %s)",username,format.Pod(pod),container.Name)default:returnnil}}
这里的抛错是不是很眼熟?如果 uid 为 0 则返回我们上面说到的 container has runAsNonRoot and image will run as root 错误,并且阻止容器创建。
获取有效 SecurityContext
determineEffectiveSecurityContext() 方法用来确定 Pod 和 Container 中有效的 SecurityContext。
// github/kubernetes/pkg/kubelet/dockershim/docker_container.gofunc(ds*dockerService)CreateContainer(_context.Context,r*runtimeapi.CreateContainerRequest)(*runtimeapi.CreateContainerResponse,error){...securityOpts,err:=ds.getSecurityOpts(config.GetLinux().GetSecurityContext().GetSeccompProfilePath(),securityOptSeparator)iferr!=nil{returnnil,fmt.Errorf("failed to generate security options for container %q: %v",config.Metadata.Name,err)}hc.SecurityOpt=append(hc.SecurityOpt,securityOpts...)...}
// github/kubernetes/pkg/kubelet/dockershim/helpers_linux.gofunc(ds*dockerService)getSecurityOpts(seccompProfilestring,separatorrune)([]string,error){// Apply seccomp options.seccompSecurityOpts,err:=getSeccompSecurityOpts(seccompProfile,separator)iferr!=nil{returnnil,fmt.Errorf("failed to generate seccomp security options for container: %v",err)}returnseccompSecurityOpts,nil}// getSeccompSecurityOpts gets container seccomp options from container seccomp profile.// It is an experimental feature and may be promoted to official runtime api in the future.funcgetSeccompSecurityOpts(seccompProfilestring,separatorrune)([]string,error){seccompOpts,err:=getSeccompDockerOpts(seccompProfile)iferr!=nil{returnnil,err}returnfmtDockerOpts(seccompOpts,separator),nil}// fmtDockerOpts formats the docker security options using the given separator.funcfmtDockerOpts(opts[]dockerOpt,seprune)[]string{fmtOpts:=make([]string,len(opts))fori,opt:=rangeopts{fmtOpts[i]=fmt.Sprintf("%s%c%s",opt.key,sep,opt.value)}returnfmtOpts}