Skip to content

Commit

Permalink
specify the user and group to be executed for the exec of kwokctl
Browse files Browse the repository at this point in the history
  • Loading branch information
lianghao208 committed Jul 7, 2023
1 parent ef999cc commit cf87f10
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 2 deletions.
14 changes: 14 additions & 0 deletions kustomize/crd/bases/kwok.x-k8s.io_clusterexecs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ spec:
- name
type: object
type: array
securityContext:
description: SecurityContext is the user context to exec.
properties:
runAsGroup:
description: RunAsGroup is the existing gid to run exec
command in container process.
format: int64
type: integer
runAsUser:
description: RunAsUser is the existing uid to run exec
command in container process.
format: int64
type: integer
type: object
workDir:
description: WorkDir is the working directory to exec with.
type: string
Expand Down
14 changes: 14 additions & 0 deletions kustomize/crd/bases/kwok.x-k8s.io_execs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ spec:
- name
type: object
type: array
securityContext:
description: SecurityContext is the user context to exec.
properties:
runAsGroup:
description: RunAsGroup is the existing gid to run exec
command in container process.
format: int64
type: integer
runAsUser:
description: RunAsUser is the existing uid to run exec
command in container process.
format: int64
type: integer
type: object
workDir:
description: WorkDir is the working directory to exec with.
type: string
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/internalversion/exec_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type ExecTargetLocal struct {
WorkDir string
// Envs is a list of environment variables to exec with.
Envs []EnvVar
// SecurityContext is the user context to exec.
SecurityContext *SecurityContext
}

// EnvVar represents an environment variable present in a Container.
Expand All @@ -59,3 +61,11 @@ type EnvVar struct {
// Value of the environment variable.
Value string
}

// SecurityContext specifies the existing uid and gid to run exec command in container process.
type SecurityContext struct {
// RunAsUser is the existing uid to run exec command in container process.
RunAsUser *int64
// RunAsGroup is the existing gid to run exec command in container process.
RunAsGroup *int64
}
34 changes: 34 additions & 0 deletions pkg/apis/internalversion/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions pkg/apis/internalversion/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions pkg/apis/v1alpha1/exec_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type ExecTargetLocal struct {
WorkDir string `json:"workDir,omitempty"`
// Envs is a list of environment variables to exec with.
Envs []EnvVar `json:"envs,omitempty"`
// SecurityContext is the user context to exec.
SecurityContext *SecurityContext `json:"securityContext,omitempty"`
}

// EnvVar represents an environment variable present in a Container.
Expand All @@ -87,6 +89,14 @@ type EnvVar struct {
Value string `json:"value,omitempty"`
}

// SecurityContext specifies the existing uid and gid to run exec command in container process.
type SecurityContext struct {
// RunAsUser is the existing uid to run exec command in container process.
RunAsUser *int64 `json:"runAsUser,omitempty"`
// RunAsGroup is the existing gid to run exec command in container process.
RunAsGroup *int64 `json:"runAsGroup,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true

Expand Down
31 changes: 31 additions & 0 deletions pkg/apis/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/kwok/server/debugging_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func (s *Server) ExecInContainer(ctx context.Context, podName, podNamespace stri
ctx = exec.WithEnv(ctx, envs)
}

// Set the user.
if execTarget.Local.SecurityContext != nil {
ctx = exec.WithUser(ctx, execTarget.Local.SecurityContext.RunAsUser, execTarget.Local.SecurityContext.RunAsGroup)
}

// Set the working directory.
if execTarget.Local.WorkDir != "" {
ctx = exec.WithDir(ctx, execTarget.Local.WorkDir)
Expand Down
59 changes: 59 additions & 0 deletions pkg/utils/exec/cmd_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"context"
"os"
"os/exec"
"os/user"
"strconv"
"syscall"
)

Expand All @@ -47,3 +49,60 @@ func isRunning(pid int) bool {
err = process.Signal(syscall.Signal(0))
return err == nil
}

func setUser(cmd *exec.Cmd, uid, gid *int64) error {
if uid == nil && gid == nil {
return nil
}
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
if cmd.SysProcAttr.Credential == nil {
cmd.SysProcAttr.Credential = &syscall.Credential{}
}
// If both uid and gid are both set, use them directly
if uid != nil && gid != nil {
_, err := user.LookupId(strconv.Itoa(int(*uid)))
if err != nil {
return err
}
_, err = user.LookupGroupId(strconv.Itoa(int(*gid)))
if err != nil {
return err
}
cmd.SysProcAttr.Credential.Uid = uint32(*uid)
cmd.SysProcAttr.Credential.Gid = uint32(*gid)
return nil
}
// If only uid is set, use that user's gid
if uid != nil {
userInfo, err := user.LookupId(strconv.Itoa(int(*uid)))
if err != nil {
return err
}
u, err := strconv.Atoi(userInfo.Uid)
if err != nil {
return err
}
g, err := strconv.Atoi(userInfo.Gid)
if err != nil {
return err
}
cmd.SysProcAttr.Credential.Uid = uint32(u)
cmd.SysProcAttr.Credential.Gid = uint32(g)
}
// If only gid is set, use the current user's uid
if gid != nil {
userInfo, err := user.Current()
if err != nil {
return err
}
u, err := strconv.Atoi(userInfo.Uid)
if err != nil {
return err
}
cmd.SysProcAttr.Credential.Uid = uint32(u)
cmd.SysProcAttr.Credential.Gid = uint32(*gid)
}
return nil
}
8 changes: 8 additions & 0 deletions pkg/utils/exec/cmd_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package exec

import (
"context"
"fmt"
"os"
"os/exec"
"syscall"
Expand Down Expand Up @@ -47,3 +48,10 @@ func isRunning(pid int) bool {
_, err := os.FindProcess(pid)
return err == nil
}

func setUser(cmd *exec.Cmd, uid, gid *int64) error {
if uid == nil && gid == nil {
return nil
}
return fmt.Errorf("user and group are not supported in windows")
}
17 changes: 17 additions & 0 deletions pkg/utils/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ type Options struct {
Dir string
// Env is the environment variables of the command.
Env []string
// UID is the user id of the command
UID *int64
// GID is the group id of the command
GID *int64
// IOStreams contains the standard streams.
IOStreams
// PipeStdin is true if the command's stdin should be piped.
Expand All @@ -56,6 +60,8 @@ func (e *Options) deepCopy() *Options {
return &Options{
Dir: e.Dir,
Env: append([]string(nil), e.Env...),
GID: e.GID,
UID: e.UID,
IOStreams: e.IOStreams,
PipeStdin: e.PipeStdin,
Fork: e.Fork,
Expand All @@ -76,6 +82,14 @@ func WithEnv(ctx context.Context, env []string) context.Context {
return ctx
}

// WithUser returns a context with the given username and group name.
func WithUser(ctx context.Context, uid, gid *int64) context.Context {
ctx, opt := withExecOptions(ctx)
opt.UID = uid
opt.GID = gid
return ctx
}

// WithDir returns a context with the given working directory.
func WithDir(ctx context.Context, dir string) context.Context {
ctx, opt := withExecOptions(ctx)
Expand Down Expand Up @@ -171,6 +185,9 @@ func Command(ctx context.Context, name string, args ...string) (cmd *exec.Cmd, e
if opt.Env != nil {
cmd.Env = append(os.Environ(), opt.Env...)
}
if err = setUser(cmd, opt.UID, opt.GID); err != nil {
return nil, fmt.Errorf("cmd set user: %s %s: %w", name, strings.Join(args, " "), err)
}

cmd.Dir = opt.Dir

Expand Down
Loading

0 comments on commit cf87f10

Please sign in to comment.