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 Jun 27, 2023
1 parent 876ac0f commit d2ad1f3
Show file tree
Hide file tree
Showing 12 changed files with 245 additions and 1 deletion.
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
// User is the user to exec.
User *User
}

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

// User specifies the existing uid and gid to run exec command in container process.
type User 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 @@ -59,6 +59,8 @@ type ExecTargetLocal struct {
WorkDir string `json:"workDir,omitempty"`
// Envs is a list of environment variables to exec with.
Envs []EnvVar `json:"envs,omitempty"`
// User is the user to exec.
User *User `json:"user,omitempty"`
}

// EnvVar represents an environment variable present in a Container.
Expand All @@ -68,3 +70,11 @@ type EnvVar struct {
// Value of the environment variable.
Value string `json:"value,omitempty"`
}

// User specifies the existing uid and gid to run exec command in container process.
type User 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"`
}
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.User != nil {
ctx = exec.WithUser(ctx, execTarget.Local.User.RunAsUser, execTarget.Local.User.RunAsGroup)
}

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

"sigs.k8s.io/kwok/pkg/log"
)

func startProcess(ctx context.Context, name string, arg ...string) *exec.Cmd {
Expand All @@ -47,3 +51,27 @@ func isRunning(pid int) bool {
err = process.Signal(syscall.Signal(0))
return err == nil
}

func setUser(ctx context.Context, uid, gid *int64, cmd *exec.Cmd) error {
logger := log.FromContext(ctx)

u, err := user.LookupId(strconv.Itoa(int(*uid)))
if err != nil {
logger.Error("failed to lookup user", err)
return err
}
g, err := user.LookupGroupId(strconv.Itoa(int(*gid)))
if err != nil {
logger.Error("failed to lookup group", err)
return err
}

logger.Info("uid", u.Uid, "username", u.Username, "gid", gid, "group name", g.Name)
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(*uid),
Gid: uint32(*gid),
},
}
return nil
}
9 changes: 9 additions & 0 deletions pkg/utils/exec/cmd_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"syscall"

"golang.org/x/sys/windows"

"sigs.k8s.io/kwok/pkg/log"
)

func startProcess(ctx context.Context, name string, arg ...string) *exec.Cmd {
Expand All @@ -47,3 +49,10 @@ func isRunning(pid int) bool {
_, err := os.FindProcess(pid)
return err == nil
}

func setUser(ctx context.Context, uid, gid *int64, cmd *exec.Cmd) error {
logger := log.FromContext(ctx)
err := "user and group are not supported in windows, ignoring the custom user and group"
logger.Warn(err)
return nil
}
17 changes: 17 additions & 0 deletions pkg/utils/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ type execOptions 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 @@ -65,6 +69,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 @@ -141,6 +153,11 @@ func Exec(ctx context.Context, name string, arg ...string) error {
cmd.Env = opt.Env
cmd.Env = append(os.Environ(), cmd.Env...)
}
if opt.UID != nil && opt.GID != nil {
if err := setUser(ctx, opt.UID, opt.GID, cmd); err != nil {
return fmt.Errorf("cmd set user: %s %s: %w", name, strings.Join(arg, " "), err)
}
}
cmd.Dir = opt.Dir
if opt.In != nil {
if opt.PipeStdin {
Expand Down
56 changes: 56 additions & 0 deletions site/content/en/docs/generated/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -3219,6 +3219,19 @@ string
<p>Envs is a list of environment variables to exec with.</p>
</td>
</tr>
<tr>
<td>
<code>user</code>
<em>
<a href="#kwok.x-k8s.io/v1alpha1.User">
User
</a>
</em>
</td>
<td>
<p>User is the user to exec.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="kwok.x-k8s.io/v1alpha1.ExpressionFromSource">
Expand Down Expand Up @@ -4355,3 +4368,46 @@ bool
</tr>
</tbody>
</table>
<h3 id="kwok.x-k8s.io/v1alpha1.User">
User
<a href="#kwok.x-k8s.io%2fv1alpha1.User"> #</a>
</h3>
<p>
<em>Appears on: </em>
<a href="#kwok.x-k8s.io/v1alpha1.ExecTargetLocal">ExecTargetLocal</a>
</p>
<p>
<p>User specifies the existing uid and gid to run exec command in container process.</p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>runAsUser</code>
<em>
int64
</em>
</td>
<td>
<p>RunAsUser is the existing uid to run exec command in container process.</p>
</td>
</tr>
<tr>
<td>
<code>runAsGroup</code>
<em>
int64
</em>
</td>
<td>
<p>RunAsGroup is the existing gid to run exec command in container process.</p>
</td>
</tr>
</tbody>
</table>
3 changes: 3 additions & 0 deletions test/kwokctl/exec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ spec:
envs:
- name: TEST_ENV
value: test
user:
runAsUser: 1001
runAsGroup: 1002
Loading

0 comments on commit d2ad1f3

Please sign in to comment.