mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-08-18 16:27:02 +00:00
Check for user+admin validity before actions (#575)
This commit is contained in:
parent
a3aadbbaa9
commit
97d25b8993
@ -29,9 +29,7 @@ import (
|
|||||||
"github.com/kairos-io/kairos-sdk/utils"
|
"github.com/kairos-io/kairos-sdk/utils"
|
||||||
qr "github.com/mudler/go-nodepair/qrcode"
|
qr "github.com/mudler/go-nodepair/qrcode"
|
||||||
"github.com/mudler/go-pluggable"
|
"github.com/mudler/go-pluggable"
|
||||||
yip "github.com/mudler/yip/pkg/schema"
|
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
"github.com/twpayne/go-vfs/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func displayInfo(agentConfig *Config) {
|
func displayInfo(agentConfig *Config) {
|
||||||
@ -217,27 +215,9 @@ func RunInstall(c *config.Config) error {
|
|||||||
utils.SetEnv(c.Env)
|
utils.SetEnv(c.Env)
|
||||||
utils.SetEnv(c.Install.Env)
|
utils.SetEnv(c.Install.Env)
|
||||||
|
|
||||||
// If nousers is enabled we do not check for the validity of the users and such
|
err := c.CheckForUsers()
|
||||||
// At this point, the config should be fully parsed and the yip stages ready
|
if err != nil {
|
||||||
if !c.Install.NoUsers {
|
return err
|
||||||
found := false
|
|
||||||
cc, _ := c.Config.String()
|
|
||||||
yamlConfig, err := yip.Load(cc, vfs.OSFS, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, stage := range yamlConfig.Stages {
|
|
||||||
for _, x := range stage {
|
|
||||||
if len(x.Users) > 0 {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("No users found in any stage\nWe require at least one user or the install option 'install.nousers: true' to be set in the config in order to allow installing a system with no users.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UKI path. Check if we are on UKI AND if we are running off a cd, otherwise it makes no sense to run the install
|
// UKI path. Check if we are on UKI AND if we are running off a cd, otherwise it makes no sense to run the install
|
||||||
|
@ -38,6 +38,10 @@ func reset(reboot, unattended, resetOem bool, dir ...string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = cfg.CheckForUsers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Load the installation Config from the cloud-config data
|
// Load the installation Config from the cloud-config data
|
||||||
resetSpec, err := config.ReadResetSpecFromConfig(cfg)
|
resetSpec, err := config.ReadResetSpecFromConfig(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,6 +69,10 @@ func resetUki(reboot, unattended, resetOem bool, dir ...string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = cfg.CheckForUsers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Load the installation Config from the cloud-config data
|
// Load the installation Config from the cloud-config data
|
||||||
resetSpec, err := config.ReadUkiResetSpecFromConfig(cfg)
|
resetSpec, err := config.ReadUkiResetSpecFromConfig(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/action"
|
"github.com/kairos-io/kairos-agent/v2/pkg/action"
|
||||||
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/uki"
|
"github.com/kairos-io/kairos-agent/v2/pkg/uki"
|
||||||
internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
internalutils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
||||||
events "github.com/kairos-io/kairos-sdk/bus"
|
events "github.com/kairos-io/kairos-sdk/bus"
|
||||||
@ -64,6 +63,7 @@ func ListNewerReleases(includePrereleases bool) ([]string, error) {
|
|||||||
return tagList.FullImages()
|
return tagList.FullImages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Check where force and preReleases is being used? They dont seem to be used anywhere?
|
||||||
func Upgrade(
|
func Upgrade(
|
||||||
source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
|
source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
|
||||||
bus.Manager.Initialize()
|
bus.Manager.Initialize()
|
||||||
@ -71,16 +71,27 @@ func Upgrade(
|
|||||||
if internalutils.UkiBootMode() == internalutils.UkiHDD {
|
if internalutils.UkiBootMode() == internalutils.UkiHDD {
|
||||||
return upgradeUki(source, dirs, upgradeEntry, strictValidations)
|
return upgradeUki(source, dirs, upgradeEntry, strictValidations)
|
||||||
} else {
|
} else {
|
||||||
return upgrade(source, force, strictValidations, dirs, upgradeEntry, preReleases)
|
return upgrade(source, dirs, upgradeEntry, strictValidations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgrade(source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
|
func upgrade(sourceImageURL string, dirs []string, upgradeEntry string, strictValidations bool) error {
|
||||||
upgradeSpec, c, err := generateUpgradeSpec(source, force, strictValidations, dirs, upgradeEntry, preReleases)
|
c, err := getConfig(sourceImageURL, dirs, upgradeEntry, strictValidations)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.SetEnv(c.Env)
|
||||||
|
|
||||||
|
err = c.CheckForUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the upgrade Config from the system
|
||||||
|
upgradeSpec, err := config.ReadUpgradeSpecFromConfig(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
err = upgradeSpec.Sanitize()
|
err = upgradeSpec.Sanitize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -96,6 +107,55 @@ func upgrade(source string, force, strictValidations bool, dirs []string, upgrad
|
|||||||
return hook.Run(*c, upgradeSpec, hook.AfterUpgrade...)
|
return hook.Run(*c, upgradeSpec, hook.AfterUpgrade...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func upgradeUki(sourceImageURL string, dirs []string, upgradeEntry string, strictValidations bool) error {
|
||||||
|
c, err := getConfig(sourceImageURL, dirs, upgradeEntry, strictValidations)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
utils.SetEnv(c.Env)
|
||||||
|
|
||||||
|
err = c.CheckForUsers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the upgrade Config from the system
|
||||||
|
upgradeSpec, err := config.ReadUkiUpgradeSpecFromConfig(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = upgradeSpec.Sanitize()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
upgradeAction := uki.NewUpgradeAction(c, upgradeSpec)
|
||||||
|
|
||||||
|
err = upgradeAction.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook.Run(*c, upgradeSpec, hook.AfterUpgrade...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfig(sourceImageURL string, dirs []string, upgradeEntry string, strictValidations bool) (*config.Config, error) {
|
||||||
|
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeEntry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := config.Scan(collector.Directories(dirs...),
|
||||||
|
collector.Readers(strings.NewReader(cliConf)),
|
||||||
|
collector.StrictValidation(strictValidations))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func allReleases() (versioneer.TagList, error) {
|
func allReleases() (versioneer.TagList, error) {
|
||||||
artifact, err := versioneer.NewArtifactFromOSRelease()
|
artifact, err := versioneer.NewArtifactFromOSRelease()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,30 +215,6 @@ func generateUpgradeConfForCLIArgs(source, upgradeEntry string) (string, error)
|
|||||||
return string(d), err
|
return string(d), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateUpgradeSpec(sourceImageURL string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) (*v1.UpgradeSpec, *config.Config, error) {
|
|
||||||
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeEntry)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := config.Scan(collector.Directories(dirs...),
|
|
||||||
collector.Readers(strings.NewReader(cliConf)),
|
|
||||||
collector.StrictValidation(strictValidations))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.SetEnv(c.Env)
|
|
||||||
|
|
||||||
// Load the upgrade Config from the system
|
|
||||||
upgradeSpec, err := config.ReadUpgradeSpecFromConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return upgradeSpec, c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getReleasesFromProvider(includePrereleases bool) ([]string, error) {
|
func getReleasesFromProvider(includePrereleases bool) ([]string, error) {
|
||||||
var result []string
|
var result []string
|
||||||
bus.Manager.Response(events.EventAvailableReleases, func(p *pluggable.Plugin, r *pluggable.EventResponse) {
|
bus.Manager.Response(events.EventAvailableReleases, func(p *pluggable.Plugin, r *pluggable.EventResponse) {
|
||||||
@ -199,42 +235,6 @@ func getReleasesFromProvider(includePrereleases bool) ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgradeUki(source string, dirs []string, upgradeEntry string, strictValidations bool) error {
|
|
||||||
cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeEntry)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := config.Scan(collector.Directories(dirs...),
|
|
||||||
collector.Readers(strings.NewReader(cliConf)),
|
|
||||||
collector.StrictValidation(strictValidations))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.SetEnv(c.Env)
|
|
||||||
|
|
||||||
// Load the upgrade Config from the system
|
|
||||||
upgradeSpec, err := config.ReadUkiUpgradeSpecFromConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = upgradeSpec.Sanitize()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
upgradeAction := uki.NewUpgradeAction(c, upgradeSpec)
|
|
||||||
|
|
||||||
err = upgradeAction.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook.Run(*c, upgradeSpec, hook.AfterUpgrade...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtraConfigUpgrade is the struct that holds the upgrade options that come from flags and events
|
// ExtraConfigUpgrade is the struct that holds the upgrade options that come from flags and events
|
||||||
type ExtraConfigUpgrade struct {
|
type ExtraConfigUpgrade struct {
|
||||||
Upgrade struct {
|
Upgrade struct {
|
||||||
|
@ -189,6 +189,54 @@ func (c Config) LoadInstallState() (*v1.InstallState, error) {
|
|||||||
return installState, nil
|
return installState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func contains(s []string, str string) bool {
|
||||||
|
for _, v := range s {
|
||||||
|
if v == str {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckForUsers will check the config for any users and validate that at least we have 1 admin.
|
||||||
|
// Since Kairos 3.3.x we don't ship a default user with the system, so before a system with no specific users
|
||||||
|
// was relying in our default cloud-configs which created a kairos user ALWAYS (with SUDO!)
|
||||||
|
// But now we don't ship it anymore. So a user upgrading from 3.2.x to 3.3.x that created no users, will end up with a blocked
|
||||||
|
// system.
|
||||||
|
// So we need to see if they are setting a user in their config and if not refuse to continue
|
||||||
|
func (c Config) CheckForUsers() (err error) {
|
||||||
|
// If nousers is enabled we do not check for the validity of the users and such
|
||||||
|
// At this point, the config should be fully parsed and the yip stages ready
|
||||||
|
if !c.Install.NoUsers {
|
||||||
|
anyAdmin := false
|
||||||
|
cc, _ := c.Config.String()
|
||||||
|
yamlConfig, err := yip.Load(cc, vfs.OSFS, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, stage := range yamlConfig.Stages {
|
||||||
|
for _, x := range stage {
|
||||||
|
if len(x.Users) > 0 {
|
||||||
|
for _, user := range x.Users {
|
||||||
|
if contains(user.Groups, "admin") || user.PrimaryGroup == "admin" {
|
||||||
|
anyAdmin = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if !anyAdmin {
|
||||||
|
return fmt.Errorf("No users found in any stage that are part of the 'admin' group.\n" +
|
||||||
|
"In Kairos 3.3.x we no longer ship a default hardcoded user with the system configs and require users to provide their own user." +
|
||||||
|
"Please provide at least 1 user that is part of the 'admin' group(for sudo) with your cloud configs." +
|
||||||
|
"If you still want to continue without creating any users in the system, set 'install.nousers: true' to be in the config in order to allow a system with no users.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Sanitize checks the consistency of the struct, returns error
|
// Sanitize checks the consistency of the struct, returns error
|
||||||
// if unsolvable inconsistencies are found
|
// if unsolvable inconsistencies are found
|
||||||
func (c *Config) Sanitize() error {
|
func (c *Config) Sanitize() error {
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
pkgConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
||||||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
@ -265,4 +266,40 @@ var _ = Describe("Schema", func() {
|
|||||||
Expect(err).Should(HaveOccurred())
|
Expect(err).Should(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("Validate users in config", func() {
|
||||||
|
It("Validates a existing user in the system", func() {
|
||||||
|
cc := `#cloud-config
|
||||||
|
stages:
|
||||||
|
initramfs:
|
||||||
|
- name: "Set user and password"
|
||||||
|
users:
|
||||||
|
kairos:
|
||||||
|
passwd: "kairos"
|
||||||
|
groups:
|
||||||
|
- "admin"
|
||||||
|
`
|
||||||
|
config, err := pkgConfig.Scan(collector.Readers(strings.NewReader(cc)), collector.NoLogs)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(config.CheckForUsers()).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("Fails if there is no user", func() {
|
||||||
|
config, err := pkgConfig.Scan()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(config.CheckForUsers()).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("Fails if there is user but its not admin", func() {
|
||||||
|
cc := `#cloud-config
|
||||||
|
stages:
|
||||||
|
initramfs:
|
||||||
|
- name: "Set user and password"
|
||||||
|
users:
|
||||||
|
kairos:
|
||||||
|
passwd: "kairos"
|
||||||
|
`
|
||||||
|
config, err := pkgConfig.Scan(collector.Readers(strings.NewReader(cc)), collector.NoLogs)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(config.CheckForUsers()).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user