-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added ability to create OS users #44
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#!/bin/bash | ||
set -euo pipefail | ||
|
||
# Without this, the script will run successfully during combustion, but when /home | ||
# is mounted it will hide the /home used during these user creations. | ||
mount /home | ||
|
||
{{ range . }} | ||
|
||
{{/* Non-root users */}} | ||
{{ if (ne .Username "root") }} | ||
useradd -m {{.Username}} | ||
{{ if .Password }} | ||
echo '{{.Username}}:{{.Password}}' | chpasswd -e | ||
{{ end }} | ||
{{ if .SSHKey }} | ||
mkdir -pm700 /home/{{.Username}}/.ssh/ | ||
echo '{{.SSHKey}}' >> /home/{{.Username}}/.ssh/authorized_keys | ||
chown -R {{.Username}} /home/{{.Username}}/.ssh | ||
{{ end }} | ||
{{ end }} | ||
|
||
{{/* Root */}} | ||
{{ if (eq .Username "root") }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a particular reason not to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing specific. My head was in a different place editing a template v. code so I just wasn't thinking of it as a if/else construct so much as a flag for inclusion (not sure if that made sense). |
||
{{ if .Password }} | ||
echo '{{.Username}}:{{.Password}}' | chpasswd -e | ||
{{ end }} | ||
{{ if .SSHKey }} | ||
mkdir -pm700 /{{.Username}}/.ssh/ | ||
echo '{{.SSHKey}}' >> /{{.Username}}/.ssh/authorized_keys | ||
{{ end }} | ||
{{ end }} | ||
|
||
{{ end }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package build | ||
|
||
import ( | ||
_ "embed" | ||
"fmt" | ||
"os" | ||
) | ||
|
||
const ( | ||
usersScriptName = "add-users.sh" | ||
userScriptMode = 0o744 | ||
) | ||
|
||
//go:embed scripts/users/add-users.sh.tpl | ||
var usersScript string | ||
|
||
func (b *Builder) configureUsers() error { | ||
// Punch out early if there are no users | ||
if len(b.imageConfig.OperatingSystem.Users) == 0 { | ||
return nil | ||
} | ||
|
||
filename, err := b.writeCombustionFile(usersScriptName, usersScript, b.imageConfig.OperatingSystem.Users) | ||
if err != nil { | ||
return fmt.Errorf("writing %s to the combustion directory: %w", usersScriptName, err) | ||
} | ||
err = os.Chmod(filename, userScriptMode) | ||
if err != nil { | ||
return fmt.Errorf("modifying permissions for script %s: %w", filename, err) | ||
} | ||
|
||
b.registerCombustionScript(usersScriptName) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package build | ||
|
||
import ( | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/suse-edge/edge-image-builder/pkg/config" | ||
) | ||
|
||
func TestConfigureUsers(t *testing.T) { | ||
// Setup | ||
imageConfig := &config.ImageConfig{ | ||
OperatingSystem: config.OperatingSystem{ | ||
Users: []config.OperatingSystemUser{ | ||
{ | ||
Username: "alpha", | ||
Password: "alpha123", | ||
SSHKey: "alphakey", | ||
}, | ||
{ | ||
Username: "beta", | ||
Password: "beta123", | ||
}, | ||
{ | ||
Username: "gamma", | ||
SSHKey: "gammakey", | ||
}, | ||
{ | ||
Username: "root", | ||
Password: "root123", | ||
SSHKey: "rootkey", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
context, err := NewContext("", "", true) | ||
require.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, CleanUpBuildDir(context)) | ||
}() | ||
|
||
builder := &Builder{ | ||
imageConfig: imageConfig, | ||
context: context, | ||
} | ||
|
||
// Test | ||
err = builder.configureUsers() | ||
|
||
// Verify | ||
require.NoError(t, err) | ||
|
||
expectedFilename := filepath.Join(context.CombustionDir, usersScriptName) | ||
foundBytes, err := os.ReadFile(expectedFilename) | ||
require.NoError(t, err) | ||
|
||
stats, err := os.Stat(expectedFilename) | ||
require.NoError(t, err) | ||
assert.Equal(t, fs.FileMode(userScriptMode), stats.Mode()) | ||
|
||
foundContents := string(foundBytes) | ||
|
||
// - All fields specified | ||
assert.Contains(t, foundContents, "useradd -m alpha") | ||
assert.Contains(t, foundContents, "echo 'alpha:alpha123' | chpasswd -e\n") | ||
assert.Contains(t, foundContents, "mkdir -pm700 /home/alpha/.ssh/") | ||
assert.Contains(t, foundContents, "echo 'alphakey' >> /home/alpha/.ssh/authorized_keys") | ||
assert.Contains(t, foundContents, "chown -R alpha /home/alpha/.ssh") | ||
|
||
// - Only a password set | ||
assert.Contains(t, foundContents, "useradd -m beta") | ||
assert.Contains(t, foundContents, "echo 'beta:beta123' | chpasswd -e\n") | ||
assert.NotContains(t, foundContents, "mkdir -pm700 /home/beta/.ssh/") | ||
assert.NotContains(t, foundContents, "/home/beta/.ssh/authorized_keys") | ||
assert.NotContains(t, foundContents, "chown -R beta /home/beta/.ssh") | ||
|
||
// - Only an SSH key specified | ||
assert.Contains(t, foundContents, "useradd -m gamma") | ||
assert.NotContains(t, foundContents, "echo 'gamma:") | ||
assert.Contains(t, foundContents, "mkdir -pm700 /home/gamma/.ssh/") | ||
assert.Contains(t, foundContents, "echo 'gammakey' >> /home/gamma/.ssh/authorized_keys") | ||
assert.Contains(t, foundContents, "chown -R gamma /home/gamma/.ssh") | ||
|
||
// - Special handling for root | ||
assert.NotContains(t, foundContents, "useradd -m root") | ||
assert.Contains(t, foundContents, "echo 'root:root123' | chpasswd -e\n") | ||
assert.Contains(t, foundContents, "mkdir -pm700 /root/.ssh/") | ||
assert.Contains(t, foundContents, "echo 'rootkey' >> /root/.ssh/authorized_keys") | ||
assert.NotContains(t, foundContents, "chown -R root") | ||
} | ||
|
||
func TestConfigureUsers_NoUsers(t *testing.T) { | ||
// Setup | ||
context, err := NewContext("", "", true) | ||
require.NoError(t, err) | ||
defer func() { | ||
assert.NoError(t, CleanUpBuildDir(context)) | ||
}() | ||
|
||
builder := &Builder{ | ||
imageConfig: &config.ImageConfig{}, | ||
context: context, | ||
} | ||
|
||
// Test | ||
err = builder.configureUsers() | ||
|
||
// Verify | ||
require.NoError(t, err) | ||
|
||
expectedFilename := filepath.Join(context.CombustionDir, usersScriptName) | ||
_, err = os.ReadFile(expectedFilename) | ||
require.ErrorIs(t, err, os.ErrNotExist) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
apiVersion: 1.0 | ||
image: | ||
imageType: iso | ||
baseImage: slemicro5.5.iso | ||
outputImageName: eibimage.iso | ||
operatingSystem: | ||
kernelArgs: | ||
- alpha=foo | ||
- beta=bar | ||
users: | ||
- username: alpha | ||
password: $6$bZfTI3Wj05fdxQcB$W1HJQTKw/MaGTCwK75ic9putEquJvYO7vMnDBVAfuAMFW58/79abky4mx9.8znK0UZwSKng9dVosnYQR1toH71 | ||
sshKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDnb80jkq8jYqC7EeXdtmdMLoQ/qeCzFPRrNyA5H5iB3k21Oc8ccBR2nIbteam39E0p4mwR2MVNACOR0cixgWskIb5bR8KqiqLMdj4PKMLX5r1jbtcB3/6beBKPqOpk0N2NwTy5BUH8NMwRpdzcq0QeY60f1z+PLJ4vTb0mcdyRkO4m0mqGa/LrBn9H5V3AAW6TdLO9LKjvUqHX+6vWKiWu2wJffTQQAxY9rsT+JoBVk8zes06zh+CVd7bGozJXp1t6SHQjJ7V9pLNfdMO4TJFpi3mVh3RLsg24RGoMVRNCjfYaBQkUJununzpPB9O9esOhfffM2puumAkspPALMiODcYK5bzF26YvDM124e5VQJo50GqbTNJEXB7PsZF4TezivS5xCuGoO6sSrk+heWKzgnLK7/qHI55XuExBbzfTawwWpGrSOw4YYCkrCa0bPYsY8Ef5iIQMwFseWz0i57eZp2pJfn65p4osM+r08R+X8BwEvK+BsyW/wtCI06xwFtdM= [email protected] | ||
- username: beta | ||
password: $6$GHjiVHm2AT.Qxznz$1CwDuEBM1546E/sVE1Gn1y4JoGzW58wrckyx3jj2QnphFmceS6b/qFtkjw1cp7LSJNW1OcLe/EeIxDDHqZU6o1 | ||
- username: gamma | ||
sshKey: ssh-rsa BBBBB3NzaC1yc2EAAAADAQABAAABgQDnb80jkq8jYqC7EeXdtmdMLoQ/qeCzFPRrNyA5H5iB3k21Oc8ccBR2nIbteam39E0p4mwR2MVNACOR0cixgWskIb5bR8KqiqLMdj4PKMLX5r1jbtcB3/6beBKPqOpk0N2NwTy5BUH8NMwRpdzcq0QeY60f1z+PLJ4vTb0mcdyRkO4m0mqGa/LrBn9H5V3AAW6TdLO9LKjvUqHX+6vWKiWu2wJffTQQAxY9rsT+JoBVk8zes06zh+CVd7bGozJXp1t6SHQjJ7V9pLNfdMO4TJFpi3mVh3RLsg24RGoMVRNCjfYaBQkUJununzpPB9O9esOhfffM2puumAkspPALMiODcYK5bzF26YvDM124e5VQJo50GqbTNJEXB7PsZF4TezivS5xCuGoO6sSrk+heWKzgnLK7/qHI55XuExBbzfTawwWpGrSOw4YYCkrCa0bPYsY8Ef5iIQMwFseWz0i57eZp2pJfn65p4osM+r08R+X8BwEvK+BsyW/wtCI06xwFtdM= [email protected] |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the same for both cases can we extract it down below in order to avoid the repetition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO that makes it less readable, but that may be a personal distaste for the templating syntax. I like the model here where we have distinct section on root v. non-root and, IMO, that's worth the minimal duplication.