diff --git a/internal/distro/rhel8/distro.go b/internal/distro/rhel8/distro.go index c1785492f..4f6279993 100644 --- a/internal/distro/rhel8/distro.go +++ b/internal/distro/rhel8/distro.go @@ -12,7 +12,6 @@ import ( "github.com/google/uuid" "github.com/osbuild/osbuild-composer/internal/blueprint" - "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -387,12 +386,10 @@ func (t *imageType) pipeline(c *blueprint.Customizations, options distro.ImageOp p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - options, err := t.userStageOptions(users) - if err != nil { - return nil, err - } - p.AddStage(osbuild.NewUsersStage(options)) + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers()); err != nil { + return nil, err + } else if userOptions != nil { + p.AddStage(osbuild.NewUsersStage(userOptions)) } if services := c.GetServices(); services != nil || t.enabledServices != nil || t.disabledServices != nil || t.defaultTarget != "" { @@ -483,39 +480,6 @@ func (t *imageType) rpmStageOptions(arch architecture, repos []rpmmd.RepoConfig, } } -func (t *imageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { - options := osbuild.UsersStageOptions{ - Users: make(map[string]osbuild.UsersStageOptionsUser), - } - - for _, c := range users { - if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { - cryptedPassword, err := crypt.CryptSHA512(*c.Password) - if err != nil { - return nil, err - } - - c.Password = &cryptedPassword - } - - user := osbuild.UsersStageOptionsUser{ - Groups: c.Groups, - Description: c.Description, - Home: c.Home, - Shell: c.Shell, - Password: c.Password, - Key: c.Key, - } - - user.UID = c.UID - user.GID = c.GID - - options.Users[c.Name] = user - } - - return &options, nil -} - func (t *imageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, diff --git a/internal/distro/rhel84/distro.go b/internal/distro/rhel84/distro.go index 00a21807d..6ea6b53e3 100644 --- a/internal/distro/rhel84/distro.go +++ b/internal/distro/rhel84/distro.go @@ -15,7 +15,6 @@ import ( "github.com/google/uuid" "github.com/osbuild/osbuild-composer/internal/blueprint" - "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/rpmmd" ) @@ -459,12 +458,10 @@ func (t *imageType) pipeline(c *blueprint.Customizations, options distro.ImageOp p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - options, err := t.userStageOptions(users) - if err != nil { - return nil, err - } - p.AddStage(osbuild.NewUsersStage(options)) + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers()); err != nil { + return nil, err + } else if userOptions != nil { + p.AddStage(osbuild.NewUsersStage(userOptions)) } if services := c.GetServices(); services != nil || t.enabledServices != nil || t.disabledServices != nil || t.defaultTarget != "" { @@ -567,39 +564,6 @@ func (t *imageType) rpmStageOptions(arch architecture, repos []rpmmd.RepoConfig, } } -func (t *imageType) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { - options := osbuild.UsersStageOptions{ - Users: make(map[string]osbuild.UsersStageOptionsUser), - } - - for _, c := range users { - if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { - cryptedPassword, err := crypt.CryptSHA512(*c.Password) - if err != nil { - return nil, err - } - - c.Password = &cryptedPassword - } - - user := osbuild.UsersStageOptionsUser{ - Groups: c.Groups, - Description: c.Description, - Home: c.Home, - Shell: c.Shell, - Password: c.Password, - Key: c.Key, - } - - user.UID = c.UID - user.GID = c.GID - - options.Users[c.Name] = user - } - - return &options, nil -} - func (t *imageType) groupStageOptions(groups []blueprint.GroupCustomization) *osbuild.GroupsStageOptions { options := osbuild.GroupsStageOptions{ Groups: map[string]osbuild.GroupsStageOptionsGroup{}, diff --git a/internal/distro/rhel84/distro_v2.go b/internal/distro/rhel84/distro_v2.go index 35d42b93c..0ea0f711e 100644 --- a/internal/distro/rhel84/distro_v2.go +++ b/internal/distro/rhel84/distro_v2.go @@ -7,7 +7,6 @@ import ( "path/filepath" "strings" - "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/distro" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" @@ -321,13 +320,18 @@ func (t *imageTypeS2) ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rp p.AddStage(osbuild.NewGroupsStage(t.groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - options, err := t.userStageOptions(users) + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { + // for ostree, writing the key during user creation is redundant and + // can cause issues so create users without keys and write them on + // first boot + userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true) if err != nil { return nil, err } - p.AddStage(osbuild.NewUsersStage(options)) - p.AddStage(osbuild.NewFirstBootStage(t.usersFirstBootOptions(options))) + p.AddStage(osbuild.NewUsersStage(userOptionsSansKeys)) + p.AddStage(osbuild.NewFirstBootStage(t.usersFirstBootOptions(userOptions))) } if services := c.GetServices(); services != nil || t.enabledServices != nil || t.disabledServices != nil || t.defaultTarget != "" { @@ -528,39 +532,6 @@ func (t *imageTypeS2) selinuxStageOptions() *osbuild.SELinuxStageOptions { return options } -func (t *imageTypeS2) userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { - options := osbuild.UsersStageOptions{ - Users: make(map[string]osbuild.UsersStageOptionsUser), - } - - for _, c := range users { - if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { - cryptedPassword, err := crypt.CryptSHA512(*c.Password) - if err != nil { - return nil, err - } - - c.Password = &cryptedPassword - } - - user := osbuild.UsersStageOptionsUser{ - Groups: c.Groups, - Description: c.Description, - Home: c.Home, - Shell: c.Shell, - Password: c.Password, - Key: c.Key, - } - - user.UID = c.UID - user.GID = c.GID - - options.Users[c.Name] = user - } - - return &options, nil -} - func (t *imageTypeS2) usersFirstBootOptions(usersStageOptions *osbuild.UsersStageOptions) *osbuild.FirstBootStageOptions { cmds := make([]string, 0, 3*len(usersStageOptions.Users)+1) // workaround for creating authorized_keys file for user diff --git a/internal/distro/rhel85/pipelines.go b/internal/distro/rhel85/pipelines.go index 22b25ae16..ac2967b49 100644 --- a/internal/distro/rhel85/pipelines.go +++ b/internal/distro/rhel85/pipelines.go @@ -242,11 +242,9 @@ func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) - if err != nil { - return nil, err - } + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { p.AddStage(osbuild.NewUsersStage(userOptions)) } @@ -665,11 +663,9 @@ func osPipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, bpPackag p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) - if err != nil { - return nil, err - } + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { p.AddStage(osbuild.NewUsersStage(userOptions)) } @@ -751,12 +747,17 @@ func ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { + // for ostree, writing the key during user creation is redundant and + // can cause issues so create users without keys and write them on + // first boot + userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true) if err != nil { return nil, err } - p.AddStage(osbuild.NewUsersStage(userOptions)) + p.AddStage(osbuild.NewUsersStage(userOptionsSansKeys)) p.AddStage(osbuild.NewFirstBootStage(usersFirstBootOptions(userOptions))) } diff --git a/internal/distro/rhel85/stage_options.go b/internal/distro/rhel85/stage_options.go index 76d08c61f..631a0fefd 100644 --- a/internal/distro/rhel85/stage_options.go +++ b/internal/distro/rhel85/stage_options.go @@ -7,7 +7,6 @@ import ( "github.com/osbuild/osbuild-composer/internal/blueprint" "github.com/osbuild/osbuild-composer/internal/common" - "github.com/osbuild/osbuild-composer/internal/crypt" "github.com/osbuild/osbuild-composer/internal/distro" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" ) @@ -32,39 +31,6 @@ func selinuxStageOptions(labelcp bool) *osbuild.SELinuxStageOptions { return options } -func userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { - options := osbuild.UsersStageOptions{ - Users: make(map[string]osbuild.UsersStageOptionsUser), - } - - for _, c := range users { - if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { - cryptedPassword, err := crypt.CryptSHA512(*c.Password) - if err != nil { - return nil, err - } - - c.Password = &cryptedPassword - } - - user := osbuild.UsersStageOptionsUser{ - Groups: c.Groups, - Description: c.Description, - Home: c.Home, - Shell: c.Shell, - Password: c.Password, - Key: c.Key, - } - - user.UID = c.UID - user.GID = c.GID - - options.Users[c.Name] = user - } - - return &options, nil -} - func usersFirstBootOptions(usersStageOptions *osbuild.UsersStageOptions) *osbuild.FirstBootStageOptions { cmds := make([]string, 0, 3*len(usersStageOptions.Users)+1) // workaround for creating authorized_keys file for user diff --git a/internal/distro/rhel86/pipelines.go b/internal/distro/rhel86/pipelines.go index 35e33067b..f7e73c012 100644 --- a/internal/distro/rhel86/pipelines.go +++ b/internal/distro/rhel86/pipelines.go @@ -429,9 +429,9 @@ func osPipeline(t *imageType, return nil, err } else if userOptions != nil { if t.rpmOstree { - // for ostree, writing the key during user creation is redundant - // and can cause issues so create users without keys and write them - // on first boot + // for ostree, writing the key during user creation is + // redundant and can cause issues so create users without keys + // and write them on first boot userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true) if err != nil { return nil, err diff --git a/internal/distro/rhel90/pipelines.go b/internal/distro/rhel90/pipelines.go index c989a28fe..48c15a66e 100644 --- a/internal/distro/rhel90/pipelines.go +++ b/internal/distro/rhel90/pipelines.go @@ -421,9 +421,9 @@ func osPipeline(t *imageType, return nil, err } else if userOptions != nil { if t.rpmOstree { - // for ostree, writing the key during user creation is redundant - // and can cause issues so create users without keys and write them - // on first boot + // for ostree, writing the key during user creation is + // redundant and can cause issues so create users without keys + // and write them on first boot userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true) if err != nil { return nil, err diff --git a/internal/distro/rhel90beta/pipelines.go b/internal/distro/rhel90beta/pipelines.go index 5ec0a0d8a..b3433a97f 100644 --- a/internal/distro/rhel90beta/pipelines.go +++ b/internal/distro/rhel90beta/pipelines.go @@ -230,11 +230,9 @@ func ec2BaseTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) - if err != nil { - return nil, err - } + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { p.AddStage(osbuild.NewUsersStage(userOptions)) } @@ -749,11 +747,9 @@ func osPipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, bpPackag p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) - if err != nil { - return nil, err - } + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { p.AddStage(osbuild.NewUsersStage(userOptions)) } @@ -830,12 +826,17 @@ func ostreeTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, p.AddStage(osbuild.NewGroupsStage(groupStageOptions(groups))) } - if users := c.GetUsers(); len(users) > 0 { - userOptions, err := userStageOptions(users) + if userOptions, err := osbuild.NewUsersStageOptions(c.GetUsers(), false); err != nil { + return nil, err + } else if userOptions != nil { + // for ostree, writing the key during user creation is redundant and + // can cause issues so create users without keys and write them on + // first boot + userOptionsSansKeys, err := osbuild.NewUsersStageOptions(c.GetUsers(), true) if err != nil { return nil, err } - p.AddStage(osbuild.NewUsersStage(userOptions)) + p.AddStage(osbuild.NewUsersStage(userOptionsSansKeys)) p.AddStage(osbuild.NewFirstBootStage(usersFirstBootOptions(userOptions))) } diff --git a/internal/distro/rhel90beta/stage_options.go b/internal/distro/rhel90beta/stage_options.go index a4ebd5d90..2d3748340 100644 --- a/internal/distro/rhel90beta/stage_options.go +++ b/internal/distro/rhel90beta/stage_options.go @@ -5,7 +5,6 @@ import ( "path/filepath" "github.com/osbuild/osbuild-composer/internal/blueprint" - "github.com/osbuild/osbuild-composer/internal/crypt" osbuild "github.com/osbuild/osbuild-composer/internal/osbuild2" ) @@ -29,39 +28,6 @@ func selinuxStageOptions(labelcp bool) *osbuild.SELinuxStageOptions { return options } -func userStageOptions(users []blueprint.UserCustomization) (*osbuild.UsersStageOptions, error) { - options := osbuild.UsersStageOptions{ - Users: make(map[string]osbuild.UsersStageOptionsUser), - } - - for _, c := range users { - if c.Password != nil && !crypt.PasswordIsCrypted(*c.Password) { - cryptedPassword, err := crypt.CryptSHA512(*c.Password) - if err != nil { - return nil, err - } - - c.Password = &cryptedPassword - } - - user := osbuild.UsersStageOptionsUser{ - Groups: c.Groups, - Description: c.Description, - Home: c.Home, - Shell: c.Shell, - Password: c.Password, - Key: c.Key, - } - - user.UID = c.UID - user.GID = c.GID - - options.Users[c.Name] = user - } - - return &options, nil -} - func usersFirstBootOptions(usersStageOptions *osbuild.UsersStageOptions) *osbuild.FirstBootStageOptions { cmds := make([]string, 0, 3*len(usersStageOptions.Users)+1) // workaround for creating authorized_keys file for user diff --git a/internal/osbuild1/users_stage.go b/internal/osbuild1/users_stage.go index dff8c02c4..1288bcf3f 100644 --- a/internal/osbuild1/users_stage.go +++ b/internal/osbuild1/users_stage.go @@ -1,5 +1,10 @@ package osbuild1 +import ( + "github.com/osbuild/osbuild-composer/internal/blueprint" + "github.com/osbuild/osbuild-composer/internal/crypt" +) + type UsersStageOptions struct { Users map[string]UsersStageOptionsUser `json:"users"` } @@ -23,3 +28,35 @@ func NewUsersStage(options *UsersStageOptions) *Stage { Options: options, } } + +func NewUsersStageOptions(userCustomizations []blueprint.UserCustomization) (*UsersStageOptions, error) { + if len(userCustomizations) == 0 { + return nil, nil + } + + users := make(map[string]UsersStageOptionsUser, len(userCustomizations)) + for _, uc := range userCustomizations { + if uc.Password != nil && !crypt.PasswordIsCrypted(*uc.Password) { + cryptedPassword, err := crypt.CryptSHA512(*uc.Password) + if err != nil { + return nil, err + } + + uc.Password = &cryptedPassword + } + + user := UsersStageOptionsUser{ + UID: uc.UID, + GID: uc.GID, + Groups: uc.Groups, + Description: uc.Description, + Home: uc.Home, + Shell: uc.Shell, + Password: uc.Password, + Key: uc.Key, + } + users[uc.Name] = user + } + + return &UsersStageOptions{Users: users}, nil +}