From 1916a16311ee324e8160675dc6fce4d397399237 Mon Sep 17 00:00:00 2001 From: James Rasell Date: Fri, 5 Sep 2025 14:07:27 +0100 Subject: [PATCH] exec: Set LOGNAME env var on exec based drivers. (#26703) Typically the `LOGNAME` environment variable should be set according to the values within `/etc/passwd` and represents the name of the logged in user. This should be set, where possible, alongside the USER and HOME variables for all drivers that use the shared executor and do not use a sub-shell. --- .changelog/26703.txt | 3 ++ drivers/shared/executor/executor_linux.go | 1 + .../shared/executor/executor_linux_test.go | 31 +++++++++++++++++++ drivers/shared/executor/executor_unix.go | 3 +- .../content/docs/job-specification/task.mdx | 4 +-- .../runtime-environment-settings.mdx | 6 ++-- 6 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 .changelog/26703.txt diff --git a/.changelog/26703.txt b/.changelog/26703.txt new file mode 100644 index 000000000..2e04af143 --- /dev/null +++ b/.changelog/26703.txt @@ -0,0 +1,3 @@ +```release-note:bug +exec: Correctly set the `LOGNAME` env var when the job specification user value is set +``` diff --git a/drivers/shared/executor/executor_linux.go b/drivers/shared/executor/executor_linux.go index 84fc3cc54..ed906a7e9 100644 --- a/drivers/shared/executor/executor_linux.go +++ b/drivers/shared/executor/executor_linux.go @@ -237,6 +237,7 @@ func (l *LibcontainerExecutor) Launch(command *ExecCommand) (*ProcessState, erro return nil, err } process.Env = append(process.Env, fmt.Sprintf("USER=%s", u.Username)) + process.Env = append(process.Env, fmt.Sprintf("LOGNAME=%s", u.Username)) process.Env = append(process.Env, fmt.Sprintf("HOME=%s", u.HomeDir)) } diff --git a/drivers/shared/executor/executor_linux_test.go b/drivers/shared/executor/executor_linux_test.go index 9dc94487f..d17b76798 100644 --- a/drivers/shared/executor/executor_linux_test.go +++ b/drivers/shared/executor/executor_linux_test.go @@ -865,6 +865,37 @@ func TestExecutor_UserEnv(t *testing.T) { must.Eq(t, output, "runner") } +func TestExecutor_LogNameEnv(t *testing.T) { + t.Parallel() + testutil.RequireCILinux(t) + testutil.ExecCompatible(t) + + testExecCmd := testExecutorCommandWithChroot(t) + execCmd, allocDir := testExecCmd.command, testExecCmd.allocDir + execCmd.Cmd = "/bin/bash" + execCmd.Args = []string{"-c", "echo $LOGNAME"} + execCmd.User = "runner" + execCmd.ResourceLimits = true + defer allocDir.Destroy() + + executor := NewExecutorWithIsolation(testlog.HCLogger(t), compute) + defer executor.Shutdown("SIGKILL", 0) + + ps, err := executor.Launch(execCmd) + must.NoError(t, err) + must.NonZero(t, ps.Pid) + + state, err := executor.Wait(context.Background()) + must.NoError(t, err) + must.Zero(t, state.ExitCode) + + _, ok := executor.(*LibcontainerExecutor) + must.True(t, ok) + + output := strings.TrimSpace(testExecCmd.stdout.String()) + must.Eq(t, output, "runner") +} + func TestExecCommand_getCgroupOr_off(t *testing.T) { ci.Parallel(t) diff --git a/drivers/shared/executor/executor_unix.go b/drivers/shared/executor/executor_unix.go index c241a3bc4..960988212 100644 --- a/drivers/shared/executor/executor_unix.go +++ b/drivers/shared/executor/executor_unix.go @@ -101,8 +101,9 @@ func setCmdUser(cmd *exec.Cmd, userid string) error { cmd.SysProcAttr.Credential.Gid = uint32(gid) cmd.SysProcAttr.Credential.Groups = gids - // Override HOME and USER environment variables + // Override USER, LOGNAME, and HOME environment variables. cmd.Env = append(cmd.Env, fmt.Sprintf("USER=%s", u.Username)) + cmd.Env = append(cmd.Env, fmt.Sprintf("LOGNAME=%s", u.Username)) cmd.Env = append(cmd.Env, fmt.Sprintf("HOME=%s", u.HomeDir)) return nil diff --git a/website/content/docs/job-specification/task.mdx b/website/content/docs/job-specification/task.mdx index df1e14b23..fe3eb0ea8 100644 --- a/website/content/docs/job-specification/task.mdx +++ b/website/content/docs/job-specification/task.mdx @@ -110,8 +110,8 @@ job "docs" { [Docker][] images specify their own default users. Clients can restrict [which drivers][user_drivers] are allowed to run tasks as [certain users][user_denylist]. On UNIX-like systems, setting `user` also affects - the environment variables `HOME` and `USER` available to the task. On - Windows, when Nomad is running as a [system service][service] for the + the environment variables `HOME`, `USER`, and `LOGNAME` available to the task. + On Windows, when Nomad is running as a [system service][service] for the [`raw_exec`][raw_exec] driver, you may specify a less-privileged service user. For example, `NT AUTHORITY\LocalService`, `NT AUTHORITY\NetworkService`. diff --git a/website/content/docs/reference/runtime-environment-settings.mdx b/website/content/docs/reference/runtime-environment-settings.mdx index 2773d7cc0..4d35a2f36 100644 --- a/website/content/docs/reference/runtime-environment-settings.mdx +++ b/website/content/docs/reference/runtime-environment-settings.mdx @@ -112,9 +112,9 @@ behavior. Nomad passes the environment variables defined in the client host to tasks when using the `exec`, `raw_exec`, and `java` task drivers. Nomad also modifies -`HOME` and `USER` variables for tasks that have the `user` parameter set, to -reflect the set username. The variables that are passed to the tasks can be -controlled using the client configuration [`env.denylist`][]. +`HOME`, `USER`, and `LOGNAME` variables for tasks that have the `user` parameter +set, to reflect the set username. The variables that are passed to the tasks can +be controlled using the client configuration [`env.denylist`][]. [jobspec]: /nomad/docs/job-specification 'Nomad Job Specification' [filesystem internals]: /nomad/docs/concepts/filesystem