Skip to content

Commit

Permalink
honor task user when execing into raw_exec task (#9439)
Browse files Browse the repository at this point in the history
Fix #9210 .

This update the executor so it honors the User when using nomad alloc exec. The bug was that the exec task didn't honor the init command when execing.
  • Loading branch information
Mahmood Ali authored Nov 25, 2020
1 parent c83352f commit edaa165
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ IMPROVEMENTS:
* csi: Relaxed validation requirements when checking volume capabilities with controller plugins, to accommodate existing plugin behaviors. [[GH-9049](https://github.com/hashicorp/nomad/issues/9049)]
* driver/docker: Upgrade pause container and detect architecture [[GH-8957](https://github.com/hashicorp/nomad/pull/8957)]
* driver/docker: Support pinning tasks to specific CPUs with `cpuset_cpus` option. [[GH-8291](https://github.com/hashicorp/nomad/pull/8291)]
* driver/raw_exec: Honor the task user setting when a user runs `nomad alloc exec` [[GH-9439](https://github.com/hashicorp/nomad/pull/9439)]
* jobspec: Lowered minimum CPU allowed from 10 to 1. [[GH-8996](https://github.com/hashicorp/nomad/issues/8996)]
* jobspec: Added support for `headers` option in `artifact` stanza [[GH-9306](https://github.com/hashicorp/nomad/issues/9306)]

Expand Down
39 changes: 39 additions & 0 deletions drivers/rawexec/driver_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,45 @@ func TestRawExec_ExecTaskStreaming(t *testing.T) {

}

func TestRawExec_ExecTaskStreaming_User(t *testing.T) {
t.Parallel()
if runtime.GOOS != "linux" {
t.Skip("skip, requires running on Linux for testing custom user setting")
}

d := newEnabledRawExecDriver(t)
harness := dtestutil.NewDriverHarness(t, d)
defer harness.Kill()

task := &drivers.TaskConfig{
ID: uuid.Generate(),
Name: "sleep",
User: "nobody",
}

cleanup := harness.MkAllocDir(task, false)
defer cleanup()

err := os.Chmod(task.AllocDir, 0777)
require.NoError(t, err)

tc := &TaskConfig{
Command: "/bin/sleep",
Args: []string{"9000"},
}
require.NoError(t, task.EncodeConcreteDriverConfig(&tc))
testtask.SetTaskConfigEnv(task)

_, _, err = harness.StartTask(task)
require.NoError(t, err)
defer d.DestroyTask(task.ID, true)

code, stdout, stderr := dtestutil.ExecTask(t, harness, task.ID, "whoami", false, "")
require.Zero(t, code)
require.Empty(t, stderr)
require.Contains(t, stdout, "nobody")
}

func TestRawExecDriver_NoCgroup(t *testing.T) {
t.Parallel()
if runtime.GOOS != "linux" {
Expand Down
8 changes: 7 additions & 1 deletion drivers/shared/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func (e *UniversalExecutor) Launch(command *ExecCommand) (*ProcessState, error)
// setting the user of the process
if command.User != "" {
e.logger.Debug("running command as user", "user", command.User)
if err := e.runAs(command.User); err != nil {
if err := setCmdUser(&e.childCmd, command.User); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -408,6 +408,12 @@ func (e *UniversalExecutor) ExecStreaming(ctx context.Context, command []string,
return nil
},
processStart: func() error {
if u := e.commandCfg.User; u != "" {
if err := setCmdUser(cmd, u); err != nil {
return err
}
}

return withNetworkIsolation(cmd.Start, e.commandCfg.NetworkIsolation)
},
processWait: func() (*os.ProcessState, error) {
Expand Down
6 changes: 4 additions & 2 deletions drivers/shared/executor/executor_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package executor

import (
"os/exec"

hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/nomad/plugins/drivers"
)
Expand All @@ -15,8 +17,6 @@ func NewExecutorWithIsolation(logger hclog.Logger) Executor {

func (e *UniversalExecutor) configureResourceContainer(_ int) error { return nil }

func (e *UniversalExecutor) runAs(_ string) error { return nil }

func (e *UniversalExecutor) getAllPids() (map[int]*nomadPid, error) {
return getAllPidsByScanning()
}
Expand All @@ -28,3 +28,5 @@ func (e *UniversalExecutor) start(command *ExecCommand) error {
func withNetworkIsolation(f func() error, _ *drivers.NetworkIsolationSpec) error {
return f()
}

func setCmdUser(*exec.Cmd, string) error { return nil }
21 changes: 10 additions & 11 deletions drivers/shared/executor/executor_universal_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package executor
import (
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
"syscall"
Expand All @@ -16,9 +17,9 @@ import (
"github.com/opencontainers/runc/libcontainer/specconv"
)

// runAs takes a user id as a string and looks up the user, and sets the command
// setCmdUser takes a user id as a string and looks up the user, and sets the command
// to execute as that user.
func (e *UniversalExecutor) runAs(userid string) error {
func setCmdUser(cmd *exec.Cmd, userid string) error {
u, err := user.Lookup(userid)
if err != nil {
return fmt.Errorf("Failed to identify user %v: %v", userid, err)
Expand Down Expand Up @@ -51,17 +52,15 @@ func (e *UniversalExecutor) runAs(userid string) error {
}

// Set the command to run as that user and group.
if e.childCmd.SysProcAttr == nil {
e.childCmd.SysProcAttr = &syscall.SysProcAttr{}
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
if e.childCmd.SysProcAttr.Credential == nil {
e.childCmd.SysProcAttr.Credential = &syscall.Credential{}
if cmd.SysProcAttr.Credential == nil {
cmd.SysProcAttr.Credential = &syscall.Credential{}
}
e.childCmd.SysProcAttr.Credential.Uid = uint32(uid)
e.childCmd.SysProcAttr.Credential.Gid = uint32(gid)
e.childCmd.SysProcAttr.Credential.Groups = gids

e.logger.Debug("setting process user", "user", uid, "group", gid, "additional_groups", gids)
cmd.SysProcAttr.Credential.Uid = uint32(uid)
cmd.SysProcAttr.Credential.Gid = uint32(gid)
cmd.SysProcAttr.Credential.Groups = gids

return nil
}
Expand Down
5 changes: 5 additions & 0 deletions plugins/drivers/testutils/exec_testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ func TestExecFSIsolation(t *testing.T, driver *DriverHarness, taskID string) {
})
}

func ExecTask(t *testing.T, driver *DriverHarness, taskID string, cmd string, tty bool, stdin string) (exitCode int, stdout, stderr string) {
r := execTask(t, driver, taskID, cmd, tty, stdin)
return r.exitCode, r.stdout, r.stderr
}

func execTask(t *testing.T, driver *DriverHarness, taskID string, cmd string, tty bool, stdin string) execResult {
stream := newTestExecStream(t, tty, stdin)

Expand Down

0 comments on commit edaa165

Please sign in to comment.