Skip to content

Commit

Permalink
create ostree user sudoers file
Browse files Browse the repository at this point in the history
In the context of compatibility with edge-management when creating image ISO artifact.
When creating an ostree user, the user is created with username and ssh-key without a password, the user has no possibility to manage the system as has no password to enter when using sudo command.
Create a sudoer file at first boot stage.
FIXES: https://issues.redhat.com/browse/THEEDGE-3837
  • Loading branch information
ldjebran committed Feb 1, 2024
1 parent 9f3c548 commit 4056c5a
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pkg/manifest/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,13 @@ func usersFirstBootOptions(users []users.User) *osbuild.FirstBootStageOptions {
cmds = append(cmds, fmt.Sprintf("mkdir -p %s", sshdir))
cmds = append(cmds, fmt.Sprintf("sh -c 'echo %q >> %q'", *user.Key, filepath.Join(sshdir, "authorized_keys")))
cmds = append(cmds, fmt.Sprintf("chown %s:%s -Rc %s", user.Name, user.Name, sshdir))
if user.Name != "root" {
sudoersPath := filepath.Join("/etc", "sudoers.d")
sudoersUserFilePath := filepath.Join(sudoersPath, user.Name)
cmds = append(cmds, fmt.Sprintf(`sh -c 'echo -e "%s\tALL=(ALL)\tNOPASSWD: ALL" >> %q'`, user.Name, sudoersUserFilePath))
cmds = append(cmds, fmt.Sprintf("chmod 440 %s", sudoersUserFilePath))
cmds = append(cmds, fmt.Sprintf("restorecon -rvF %s", sudoersPath))
}
}
}
cmds = append(cmds, fmt.Sprintf("restorecon -rvF %s", varhome))
Expand Down
72 changes: 72 additions & 0 deletions pkg/manifest/os_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package manifest
import (
"testing"

"github.com/osbuild/images/pkg/customizations/users"
"github.com/osbuild/images/pkg/osbuild"
"github.com/osbuild/images/pkg/platform"
"github.com/osbuild/images/pkg/rpmmd"
Expand Down Expand Up @@ -152,3 +153,74 @@ func TestRhcInsightsPackages(t *testing.T) {
}
CheckPkgSetInclude(t, os.getPackageSetChain(DISTRO_NULL), []string{"rhc", "subscription-manager", "insights-client"})
}

func TestCustomizationsUsersCommands(t *testing.T) {
testCases := []struct {
Name string
OSTreeRef string
UserName string
UserSSHKey string
ExpectedCommands []string
}{
{
Name: "pipeline stage commands with regular user should be valid",
OSTreeRef: "rhel/9/x86_64/edge",
UserName: "test-user",
UserSSHKey: "ssh-rsa test-user",
ExpectedCommands: []string{
"mkdir -p /var/home/test-user/.ssh",
`sh -c 'echo "ssh-rsa test-user" >> "/var/home/test-user/.ssh/authorized_keys"'`,
"chown test-user:test-user -Rc /var/home/test-user/.ssh",
`sh -c 'echo -e "test-user\tALL=(ALL)\tNOPASSWD: ALL" >> "/etc/sudoers.d/test-user"'`,
"chmod 440 /etc/sudoers.d/test-user",
"restorecon -rvF /etc/sudoers.d",
"restorecon -rvF /var/home",
"restorecon -rvF /var/roothome",
},
},
{
Name: "pipeline stages commands with root user should be valid",
OSTreeRef: "rhel/9/x86_64/edge",
UserName: "root",
UserSSHKey: "ssh-rsa test-root",
ExpectedCommands: []string{
"mkdir -p /var/roothome/.ssh",
`sh -c 'echo "ssh-rsa test-root" >> "/var/roothome/.ssh/authorized_keys"'`,
"chown root:root -Rc /var/roothome/.ssh",
"restorecon -rvF /var/home",
"restorecon -rvF /var/roothome",
},
},
{
Name: "pipeline stages commands should not be generated when OSTreeRef empty",
OSTreeRef: "",
UserName: "test-user",
UserSSHKey: "ssh-rsa test-user",
ExpectedCommands: []string{},
},
}

for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.Name, func(t *testing.T) {
os := NewTestOS()
os.OSTreeRef = testCase.OSTreeRef
os.Users = append(os.Users, users.User{Name: testCase.UserName, Key: &testCase.UserSSHKey})
pipeline := os.serialize()
// check if first boot stage exist in pipeline stages
firstBootStageExist := false
for _, s := range pipeline.Stages {
if s.Type == "org.osbuild.first-boot" {
firstBootStageExist = true
break
}
}
if len(testCase.ExpectedCommands) > 0 {
require.True(t, firstBootStageExist, "no first boot stage was generated")
CheckFirstBootStageOptions(t, pipeline.Stages, testCase.ExpectedCommands)
} else {
assert.False(t, firstBootStageExist, "first boot stage was generated")
}
})
}
}

0 comments on commit 4056c5a

Please sign in to comment.