Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions cmd/controller/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package controller

import (
"cmp"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -37,6 +38,12 @@ type Certificates struct {

// Init initializes the certificate component
func (c *Certificates) Init(ctx context.Context) error {
defaultUserNames := v1beta1.DefaultSystemUsers()
userNames := defaultUserNames
if c.ClusterSpec.Install != nil && c.ClusterSpec.Install.SystemUsers != nil {
userNames = c.ClusterSpec.Install.SystemUsers
}

eg, _ := errgroup.WithContext(ctx)
// Common CA
caCertPath := filepath.Join(c.K0sVars.CertRootDir, "ca.crt")
Expand All @@ -56,9 +63,10 @@ func (c *Certificates) Init(ctx context.Context) error {
// Changing the URL here also requires changes in the "k0s kubeconfig admin" subcommand.
kubeConfigAPIUrl := c.ClusterSpec.API.LocalURL()

apiServerUID, err := users.LookupUID(constant.ApiserverUser)
apiServerUser := cmp.Or(userNames.KubeAPIServer, defaultUserNames.KubeAPIServer)
apiServerUID, err := users.LookupUID(apiServerUser)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.ApiserverUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", apiServerUser, err)
apiServerUID = users.RootUID
logrus.WithError(err).Warn("Files with key material for kube-apiserver user will be owned by root")
}
Expand Down Expand Up @@ -113,9 +121,10 @@ func (c *Certificates) Init(ctx context.Context) error {
CAKey: caCertKey,
}

uid, err := users.LookupUID(constant.KonnectivityServerUser)
konnectivityServerUser := cmp.Or(userNames.Konnectivity, defaultUserNames.Konnectivity)
uid, err := users.LookupUID(konnectivityServerUser)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.KonnectivityServerUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", konnectivityServerUser, err)
uid = users.RootUID
logrus.WithError(err).Warn("Files with key material for konnectivity-server user will be owned by root")
}
Expand Down Expand Up @@ -153,9 +162,10 @@ func (c *Certificates) Init(ctx context.Context) error {
CAKey: caCertKey,
}

uid, err := users.LookupUID(constant.SchedulerUser)
schedulerUser := cmp.Or(userNames.KubeScheduler, defaultUserNames.KubeScheduler)
uid, err := users.LookupUID(schedulerUser)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.SchedulerUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", schedulerUser, err)
uid = users.RootUID
logrus.WithError(err).Warn("Files with key material for kube-scheduler user will be owned by root")
}
Expand Down
47 changes: 40 additions & 7 deletions cmd/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,19 +237,35 @@ func (c *command) start(ctx context.Context, flags *config.ControllerOptions, de

switch storageType {
case v1beta1.KineStorageType:
userName := constant.KineUser
if i := nodeConfig.Spec.Install; i != nil && i.SystemUsers != nil && i.SystemUsers.Kine != "" {
userName = i.SystemUsers.Kine
}
storageBackend = &controller.Kine{
Config: nodeConfig.Spec.Storage.Kine,
K0sVars: c.K0sVars,
Config: nodeConfig.Spec.Storage.Kine,
K0sVars: c.K0sVars,
UserName: userName,
}
case v1beta1.EtcdStorageType:
config := nodeConfig.Spec.Storage.Etcd
if !config.IsExternalClusterUsed() {
userName, apiServerUserName := constant.EtcdUser, constant.ApiserverUser
if i := nodeConfig.Spec.Install; i != nil && i.SystemUsers != nil {
if i.SystemUsers.Etcd != "" {
userName = i.SystemUsers.Etcd
}
if i.SystemUsers.KubeAPIServer != "" {
apiServerUserName = i.SystemUsers.KubeAPIServer
}
}
storageBackend = &controller.Etcd{
CertManager: certificateManager,
Config: config,
JoinClient: joinClient,
K0sVars: c.K0sVars,
LogLevel: c.LogLevels.Etcd,
CertManager: certificateManager,
Config: config,
JoinClient: joinClient,
K0sVars: c.K0sVars,
LogLevel: c.LogLevels.Etcd,
UserName: userName,
APIServerUserName: apiServerUserName,
}
}
default:
Expand Down Expand Up @@ -301,10 +317,15 @@ func (c *command) start(ctx context.Context, flags *config.ControllerOptions, de
enableKonnectivity := controllerMode != config.SingleNodeMode && !slices.Contains(flags.DisableComponents, constant.KonnectivityServerComponentName)

if enableKonnectivity {
userName := constant.KonnectivityServerUser
if i := nodeConfig.Spec.Install; i != nil && i.SystemUsers != nil && i.SystemUsers.Konnectivity != "" {
userName = i.SystemUsers.Konnectivity
}
nodeComponents.Add(ctx, &controller.Konnectivity{
Spec: nodeConfig.Spec.Konnectivity,
K0sVars: c.K0sVars,
LogLevel: c.LogLevels.Konnectivity,
UserName: userName,
EventEmitter: prober.NewEventEmitter(),
ServerCount: numActiveControllers.Peek,
})
Expand Down Expand Up @@ -572,17 +593,29 @@ func (c *command) start(ctx context.Context, flags *config.ControllerOptions, de
}

if !slices.Contains(flags.DisableComponents, constant.KubeSchedulerComponentName) {
userName := constant.SchedulerUser
if i := nodeConfig.Spec.Install; i != nil && i.SystemUsers != nil && i.SystemUsers.KubeScheduler != "" {
userName = i.SystemUsers.KubeScheduler
}
clusterComponents.Add(ctx, &controller.Scheduler{
LogLevel: c.LogLevels.KubeScheduler,
K0sVars: c.K0sVars,
UserName: userName,
DisableLeaderElection: singleController,
})
}

if !slices.Contains(flags.DisableComponents, constant.KubeControllerManagerComponentName) {
// controller manager running as api-server user as they both need access to same sa.key
userName := constant.ApiserverUser
if i := nodeConfig.Spec.Install; i != nil && i.SystemUsers != nil && i.SystemUsers.KubeAPIServer != "" {
userName = i.SystemUsers.KubeAPIServer
}

clusterComponents.Add(ctx, &controller.Manager{
LogLevel: c.LogLevels.KubeControllerManager,
K0sVars: c.K0sVars,
UserName: userName,
DisableLeaderElection: singleController,
ServiceClusterIPRange: nodeConfig.Spec.Network.BuildServiceCIDR(nodeConfig.Spec.PrimaryAddressFamily()),
ExtraArgs: flags.KubeControllerManagerExtraArgs,
Expand Down
20 changes: 20 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ spec:

## `spec` Key Detail

### `spec.installConfig`

| Element | Description |
|---------|-------------------------------------------------|
| `users` | System users used to run controller components. |

#### `spec.installConfig.users`

Users will be created when running `k0s install`. They will own the generated
certificates and kubeconfigs and be used to execute the supervised processes. If
they don't exist, k0s will fallback to the root user.

| Element | Description |
|---------------------|-------------------------------------------------------------------------------|
| `etcdUser` | Managed etcd user name. Default: `etcd`. |
| `kineUser` | Kine user. Default: `kube-apiserver`. |
| `konnectivityUser` | Konnectivity server user. Default: `konnectivity-server`. |
| `kubeAPIserverUser` | Kubernetes API server and controller manager user. Default: `kube-apiserver`. |
| `kubeSchedulerUser` | Kubernetes scheduler user. Default: `kube-scheduler`. |

### `spec.api`

| Element | Description |
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/k0s/v1beta1/clusterconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func canStrip(f reflect.StructField) bool {
return false
}

// InstallSpec defines the required fields for the `k0s install` command
// Installation-time settings and related runtime defaults.
type InstallSpec struct {
SystemUsers *SystemUser `json:"users,omitempty"`
}
Expand Down
16 changes: 12 additions & 4 deletions pkg/apis/k0s/v1beta1/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ package v1beta1

import "github.com/k0sproject/k0s/pkg/constant"

// SystemUser defines the user to use for each component
// System users used to run controller components. Users will be created when
// running `k0s install`. They will own the generated certificates and
// kubeconfigs and be used to execute the supervised processes. If they don't
// exist, k0s will fallback to the root user.
type SystemUser struct {
Etcd string `json:"etcdUser,omitempty"`
Kine string `json:"kineUser,omitempty"`
Konnectivity string `json:"konnectivityUser,omitempty"`
// User to use for managed etcd (default "etcd")
Etcd string `json:"etcdUser,omitempty"`
// User to use for kine (default "kube-apiserver")
Kine string `json:"kineUser,omitempty"`
// User to use for the konnectivity server (default "konnectivity-server")
Konnectivity string `json:"konnectivityUser,omitempty"`
// User to use for the Kubernetes API Server (default "kube-apiserver")
KubeAPIServer string `json:"kubeAPIserverUser,omitempty"`
// User to use for the Kubernetes scheduler (default "kube-scheduler")
KubeScheduler string `json:"kubeSchedulerUser,omitempty"`
}

Expand Down
11 changes: 7 additions & 4 deletions pkg/component/controller/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,14 @@ type egressSelectorConfig struct {
}

// Init extracts needed binaries
func (a *APIServer) Init(_ context.Context) error {
var err error
a.uid, err = users.LookupUID(constant.ApiserverUser)
func (a *APIServer) Init(_ context.Context) (err error) {
userName := constant.ApiserverUser
if i := a.ClusterConfig.Spec.Install; i != nil && i.SystemUsers != nil && i.SystemUsers.KubeAPIServer != "" {
userName = i.SystemUsers.KubeAPIServer
}
a.uid, err = users.LookupUID(userName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.ApiserverUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", userName, err)
a.uid = users.RootUID
logrus.WithError(err).Warn("Running Kubernetes API server as root")
}
Expand Down
7 changes: 3 additions & 4 deletions pkg/component/controller/controllermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import (
"github.com/k0sproject/k0s/pkg/assets"
"github.com/k0sproject/k0s/pkg/component/manager"
"github.com/k0sproject/k0s/pkg/config"
"github.com/k0sproject/k0s/pkg/constant"
"github.com/k0sproject/k0s/pkg/supervisor"
)

// Manager implement the component interface to run kube scheduler
type Manager struct {
K0sVars *config.CfgVars
LogLevel string
UserName string
DisableLeaderElection bool
ServiceClusterIPRange string
ExtraArgs string
Expand Down Expand Up @@ -54,10 +54,9 @@ var _ manager.Reconciler = (*Manager)(nil)
// Init extracts the needed binaries
func (a *Manager) Init(_ context.Context) error {
var err error
// controller manager running as api-server user as they both need access to same sa.key
a.uid, err = users.LookupUID(constant.ApiserverUser)
a.uid, err = users.LookupUID(a.UserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.ApiserverUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", a.UserName, err)
a.uid = users.RootUID
logrus.WithError(err).Warn("Running Kubernetes controller manager as root")
}
Expand Down
22 changes: 12 additions & 10 deletions pkg/component/controller/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ const etcdGID = 0

// Etcd implement the component interface to run etcd
type Etcd struct {
CertManager certificate.Manager
Config *v1beta1.EtcdConfig
JoinClient *token.JoinClient
K0sVars *config.CfgVars
LogLevel string
CertManager certificate.Manager
Config *v1beta1.EtcdConfig
JoinClient *token.JoinClient
K0sVars *config.CfgVars
LogLevel string
UserName string
APIServerUserName string

supervisor *supervisor.Supervisor
executablePath string
Expand All @@ -58,9 +60,9 @@ func (e *Etcd) Init(_ context.Context) error {
return fmt.Errorf("missing environment variable: %w", err)
}

e.uid, err = users.LookupUID(constant.EtcdUser)
e.uid, err = users.LookupUID(e.UserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.EtcdUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", e.UserName, err)
e.uid = users.RootUID
logrus.WithError(err).Warn("Running etcd as root, files with key material for etcd user will be owned by root")
}
Expand Down Expand Up @@ -272,11 +274,11 @@ func (e *Etcd) setupCerts(ctx context.Context) error {
},
}

uid, err := users.LookupUID(constant.ApiserverUser)
uid, err := users.LookupUID(e.APIServerUserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.ApiserverUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", e.APIServerUserName, err)
uid = users.RootUID
logrus.WithError(err).Warn("Files with key material for kube-apiserver user will be owned by root")
logrus.WithError(err).Warnf("Files with key material for %s user will be owned by root", e.APIServerUserName)
}

_, err = e.CertManager.EnsureCertificate(etcdCertReq, uid, e.Config.CA.CertificatesExpireAfter.Duration)
Expand Down
9 changes: 5 additions & 4 deletions pkg/component/controller/kine.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ const kineGID = 0

// Kine implement the component interface to run kine
type Kine struct {
Config *v1beta1.KineConfig
K0sVars *config.CfgVars
Config *v1beta1.KineConfig
K0sVars *config.CfgVars
UserName string

supervisor *supervisor.Supervisor
executablePath string
Expand All @@ -49,9 +50,9 @@ var _ manager.Ready = (*Kine)(nil)
func (k *Kine) Init(_ context.Context) error {
logrus.Infof("initializing kine")
var err error
k.uid, err = users.LookupUID(constant.KineUser)
k.uid, err = users.LookupUID(k.UserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.KineUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", k.UserName, err)
k.uid = users.RootUID
logrus.WithError(err).Warn("Running kine as root")
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/component/controller/konnectivity.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Konnectivity struct {
Spec *v1beta1.KonnectivitySpec // FIXME: This should be reconciled via dynamic config
K0sVars *config.CfgVars
LogLevel string
UserName string
ServerCount func() (uint, <-chan struct{})

supervisor *supervisor.Supervisor
Expand All @@ -54,9 +55,9 @@ var _ prober.Healthz = (*Konnectivity)(nil)
// Init ...
func (k *Konnectivity) Init(ctx context.Context) error {
var err error
k.uid, err = users.LookupUID(constant.KonnectivityServerUser)
k.uid, err = users.LookupUID(k.UserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.KonnectivityServerUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", k.UserName, err)
k.uid = users.RootUID
k.EmitWithPayload("error getting UID for", err)
logrus.WithError(err).Warn("Running konnectivity as root")
Expand Down
6 changes: 3 additions & 3 deletions pkg/component/controller/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import (
"github.com/k0sproject/k0s/pkg/assets"
"github.com/k0sproject/k0s/pkg/component/manager"
"github.com/k0sproject/k0s/pkg/config"
"github.com/k0sproject/k0s/pkg/constant"
"github.com/k0sproject/k0s/pkg/supervisor"
)

// Scheduler implement the component interface to run kube scheduler
type Scheduler struct {
K0sVars *config.CfgVars
LogLevel string
UserName string
DisableLeaderElection bool

supervisor *supervisor.Supervisor
Expand All @@ -40,9 +40,9 @@ const kubeSchedulerComponentName = "kube-scheduler"
// Init extracts the needed binaries
func (a *Scheduler) Init(_ context.Context) error {
var err error
a.uid, err = users.LookupUID(constant.SchedulerUser)
a.uid, err = users.LookupUID(a.UserName)
if err != nil {
err = fmt.Errorf("failed to lookup UID for %q: %w", constant.SchedulerUser, err)
err = fmt.Errorf("failed to lookup UID for %q: %w", a.UserName, err)
a.uid = users.RootUID
logrus.WithError(err).Warn("Running kube-scheduler as root")
}
Expand Down
Loading
Loading