diff --git a/pkg/cli/cmds/root.go b/pkg/cli/cmds/root.go index cbeb6ee282..ce78418be3 100644 --- a/pkg/cli/cmds/root.go +++ b/pkg/cli/cmds/root.go @@ -60,7 +60,7 @@ func sysctl(s string) (int, error) { if len(v) < 2 || v[len(v)-1] != '\n' { return 0, fmt.Errorf("invalid contents: %s", s) } - return strconv.Atoi(string(v[0])) + return strconv.Atoi(strings.Replace(string(v), "\n", "", -1)) } // cisErrors holds errors reported during diff --git a/pkg/podexecutor/staticpod.go b/pkg/podexecutor/staticpod.go index d0ed23ea7b..a4fb830333 100644 --- a/pkg/podexecutor/staticpod.go +++ b/pkg/podexecutor/staticpod.go @@ -7,7 +7,9 @@ import ( "net/http" "os" "os/exec" + "os/user" "path/filepath" + "strconv" "strings" "time" @@ -36,6 +38,7 @@ type StaticPod struct { Manifests string PullImages string Images images.Images + CISMode bool } func (s *StaticPod) Kubelet(args []string) error { @@ -176,7 +179,7 @@ func (s *StaticPod) ETCD(args executor.ETCDConfig) error { return err } - return staticpod.Run(s.Manifests, staticpod.Args{ + spa := staticpod.Args{ Annotations: map[string]string{ "etcd.k3s.io/initial": string(initial), }, @@ -197,5 +200,43 @@ func (s *StaticPod) ETCD(args executor.ETCDConfig) error { HealthPort: 2381, HealthPath: "/health", HealthProto: "HTTP", + } + + if s.CISMode { + etcdUser, err := user.Lookup("etcd") + if err != nil { + return err + } + uid, err := strconv.ParseInt(etcdUser.Uid, 10, 64) + if err != nil { + return err + } + gid, err := strconv.ParseInt(etcdUser.Gid, 10, 64) + if err != nil { + return err + } + spa.SecurityContext = &staticpod.SecurityContext{ + UID: uid, + GID: gid, + } + + for _, p := range []string{args.DataDir, filepath.Dir(args.ServerTrust.CertFile)} { + if err := chownr(p, int(uid), int(gid)); err != nil { + return err + } + } + } + + return staticpod.Run(s.Manifests, spa) +} + +// chownr recursively changes the ownership of the given +// path to the given user ID and group ID. +func chownr(path string, uid, gid int) error { + return filepath.Walk(path, func(name string, info os.FileInfo, err error) error { + if err == nil { + err = os.Chown(name, uid, gid) + } + return err }) } diff --git a/pkg/rke2/server.go b/pkg/rke2/server.go index fac900d403..fc6c9729f8 100644 --- a/pkg/rke2/server.go +++ b/pkg/rke2/server.go @@ -71,11 +71,24 @@ func setup(ctx *cli.Context, cfg Config) error { managed.RegisterDriver(&etcd.ETCD{}) - executor.Set(&podexecutor.StaticPod{ + sp := podexecutor.StaticPod{ Images: images, PullImages: pullImages, Manifests: manifests, - }) + CISMode: false, + } + + for _, f := range ctx.App.Flags { + switch t := f.(type) { + case cli.StringFlag: + if t.Name == "profile" { + sp.CISMode = true + } + default: + // nothing to do. Keep moving. + } + } + executor.Set(&sp) return nil } diff --git a/pkg/staticpod/staticpod.go b/pkg/staticpod/staticpod.go index 797422aa3c..d8871e8f60 100644 --- a/pkg/staticpod/staticpod.go +++ b/pkg/staticpod/staticpod.go @@ -20,17 +20,25 @@ import ( "k8s.io/client-go/tools/clientcmd" ) +// SecurityContext contains the relevant data +// to setup a pod's security context for execution. +type SecurityContext struct { + UID int64 + GID int64 +} + type Args struct { - Command string - Args []string - Image string - Dirs []string - Files []string - HealthPort int32 - HealthProto string - HealthPath string - CPUMillis int64 - Annotations map[string]string + Command string + Args []string + Image string + Dirs []string + Files []string + HealthPort int32 + HealthProto string + HealthPath string + CPUMillis int64 + SecurityContext *SecurityContext + Annotations map[string]string } func Run(dir string, args Args) error { @@ -176,6 +184,13 @@ func pod(args Args) (*v1.Pod, error) { } } + if args.SecurityContext != nil { + p.Spec.SecurityContext = &v1.PodSecurityContext{ + RunAsUser: &args.SecurityContext.UID, + RunAsGroup: &args.SecurityContext.GID, + } + } + addVolumes(p, args.Dirs, true) addVolumes(p, args.Files, false)