diff --git a/cmd/root.go b/cmd/root.go index 968885441fdd..14389713ff9f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -58,6 +58,7 @@ func init() { rootCmd.AddCommand(APICmd) rootCmd.AddCommand(etcdCmd) rootCmd.AddCommand(docs) + rootCmd.AddCommand(userCmd) longDesc = "k0s - The zero friction Kubernetes - https://k0sproject.io" if build.EulaNotice != "" { diff --git a/cmd/user.go b/cmd/user.go new file mode 100644 index 000000000000..de70951cd714 --- /dev/null +++ b/cmd/user.go @@ -0,0 +1,135 @@ +package cmd + +import ( + "bytes" + "encoding/base64" + + "github.com/cloudflare/cfssl/log" + "github.com/k0sproject/k0s/pkg/certificate" + "github.com/k0sproject/k0s/pkg/constant" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "html/template" + "io/ioutil" + "os" + "path" +) + +func init() { + userCreateCmd.Flags().StringVar(&groups, "groups", "", "Specify groups") + userCmd.AddCommand(userCreateCmd) +} + +var ( + groups string + + userKubeconfigTemplate = template.Must(template.New("kubeconfig").Parse(` +apiVersion: v1 +clusters: +- cluster: + server: {{.JoinURL}} + certificate-authority-data: {{.CACert}} + name: k0s +contexts: +- context: + cluster: k0s + user: {{.User}} + name: k0s +current-context: k0s +kind: Config +preferences: {} +users: +- name: {{.User}} + user: + client-certificate-data: {{.ClientCert}} + client-key-data: {{.ClientKey}} +`)) + + // userCmd creates new certs and kubeConfig for a user + userCmd = &cobra.Command{ + Use: "user", + Short: "Manage user access", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } + + userCreateCmd = &cobra.Command{ + Use: "create [username]", + Short: "Create a kubeconfig for a user", + Long: `Create a kubeconfig with a signed certificate and public key for a given user (and optionally user groups) +Note: A certificate once signed cannot be revoked for a particular user`, + Example: ` Command to create a kubeconfig for a user: + CLI argument: + $ k0s user create [username] + + optionally add groups: + $ k0s user create [username] --groups [groups]`, + RunE: func(cmd *cobra.Command, args []string) error { + // Disable logrus and cfssl logging for user commands to avoid printing debug info to stdout + logrus.SetLevel(logrus.FatalLevel) + log.Level = log.LevelFatal + + if len(args) == 0 { + return errors.New("Username is mandatory") + } + var username = args[0] + clusterConfig, err := ConfigFromYaml(cfgFile) + if err != nil { + return err + } + var config = constant.GetConfig(dataDir) + + caCert, err := ioutil.ReadFile(path.Join(config.CertRootDir, "ca.crt")) + if err != nil { + return errors.Wrapf(err, "failed to read cluster ca certificate, is the control plane initialized on this node?") + } + + caCertPath, caCertKey := path.Join(config.CertRootDir, "ca.crt"), path.Join(config.CertRootDir, "ca.key") + + if err != nil { + return err + } + + userReq := certificate.Request{ + Name: username, + CN: username, + O: groups, + CACert: caCertPath, + CAKey: caCertKey, + } + certManager := certificate.Manager{ + K0sVars: config, + } + userCert, err := certManager.EnsureCertificate(userReq, "root") + if err != nil { + return err + } + + data := struct { + CACert string + ClientCert string + ClientKey string + User string + JoinURL string + }{ + CACert: base64.StdEncoding.EncodeToString(caCert), + ClientCert: base64.StdEncoding.EncodeToString([]byte(userCert.Cert)), + ClientKey: base64.StdEncoding.EncodeToString([]byte(userCert.Key)), + User: username, + JoinURL: clusterConfig.Spec.API.APIAddress(), + } + + var buf bytes.Buffer + + err = userKubeconfigTemplate.Execute(&buf, &data) + if err != nil { + return err + } + os.Stdout.Write(buf.Bytes()) + return nil + }, + } +) diff --git a/docs/cli/k0s.md b/docs/cli/k0s.md index 9e31296c71f5..3d607f67aeb3 100644 --- a/docs/cli/k0s.md +++ b/docs/cli/k0s.md @@ -15,7 +15,7 @@ building a Kubernetes clusters a matter of just copying an executable to every h --data-dir string Data Directory for k0s (default: /var/lib/k0s). DO NOT CHANGE for an existing setup, things will break! -d, --debug Debug logging (default: false) -h, --help help for k0s - -l, --logging stringToString Logging Levels for the different components (default [etcd=info,containerd=info,konnectivity-server=1,kube-apiserver=1,kube-controller-manager=1,kube-scheduler=1,kubelet=1]) + -l, --logging stringToString Logging Levels for the different components (default [kube-scheduler=1,kubelet=1,etcd=info,containerd=info,konnectivity-server=1,kube-apiserver=1,kube-controller-manager=1]) ``` ### SEE ALSO @@ -26,7 +26,8 @@ building a Kubernetes clusters a matter of just copying an executable to every h * [k0s etcd](k0s_etcd.md) - Manage etcd cluster * [k0s server](k0s_server.md) - Run server * [k0s token](k0s_token.md) - Manage join tokens +* [k0s user](k0s_user.md) - Manage user access * [k0s version](k0s_version.md) - Print the k0s version * [k0s worker](k0s_worker.md) - Run worker -###### Auto generated by spf13/cobra on 20-Nov-2020 +###### Auto generated by spf13/cobra on 24-Nov-2020 diff --git a/docs/cli/k0s_user.md b/docs/cli/k0s_user.md new file mode 100644 index 000000000000..9d7f853adac6 --- /dev/null +++ b/docs/cli/k0s_user.md @@ -0,0 +1,29 @@ +## k0s user + +Manage user access + +``` +k0s user [flags] +``` + +### Options + +``` + -h, --help help for user +``` + +### Options inherited from parent commands + +``` + -c, --config string config file (default: ./k0s.yaml) + --data-dir string Data Directory for k0s (default: /var/lib/k0s). DO NOT CHANGE for an existing setup, things will break! + -d, --debug Debug logging (default: false) + -l, --logging stringToString Logging Levels for the different components (default [kube-scheduler=1,kubelet=1,etcd=info,containerd=info,konnectivity-server=1,kube-apiserver=1,kube-controller-manager=1]) +``` + +### SEE ALSO + +* [k0s](k0s.md) - k0s - Zero Friction Kubernetes +* [k0s user create](k0s_user_create.md) - Create a kubeconfig for a user + +###### Auto generated by spf13/cobra on 24-Nov-2020 diff --git a/docs/cli/k0s_user_create.md b/docs/cli/k0s_user_create.md new file mode 100644 index 000000000000..da4b6b923554 --- /dev/null +++ b/docs/cli/k0s_user_create.md @@ -0,0 +1,45 @@ +## k0s user create + +Create a kubeconfig for a user + +### Synopsis + +Create a kubeconfig with a signed certificate and public key for a given user (and optionally user groups) +Note: A certificate once signed cannot be revoked for a particular user + +``` +k0s user create [username] [flags] +``` + +### Examples + +``` + Command to create a kubeconfig for a user: + CLI argument: + $ k0s user create [username] + + optionally add groups: + $ k0s user create [username] --groups [groups] +``` + +### Options + +``` + --groups string Specify groups + -h, --help help for create +``` + +### Options inherited from parent commands + +``` + -c, --config string config file (default: ./k0s.yaml) + --data-dir string Data Directory for k0s (default: /var/lib/k0s). DO NOT CHANGE for an existing setup, things will break! + -d, --debug Debug logging (default: false) + -l, --logging stringToString Logging Levels for the different components (default [kube-scheduler=1,kubelet=1,etcd=info,containerd=info,konnectivity-server=1,kube-apiserver=1,kube-controller-manager=1]) +``` + +### SEE ALSO + +* [k0s user](k0s_user.md) - Manage user access + +###### Auto generated by spf13/cobra on 24-Nov-2020 diff --git a/docs/create-cluster.md b/docs/create-cluster.md index ea7daad7995d..77ae972dc17d 100644 --- a/docs/create-cluster.md +++ b/docs/create-cluster.md @@ -71,3 +71,24 @@ The on the new controller, run: ```sh k0s server "long-join-token" ``` + +## Adding a Cluster User + +To add a user to cluster, use the [user create](cli/k0s_user_create.md) command. +This will output a kubeconfig for the user, which can be used for authentication. + +On the controller, run the following to generate a kubeconfig for a user : +```shell script +k0s user create [username] +``` +### Enabling Access to Cluster Resources +To allow the user access to the cluster, the user needs to be created with the `system:masters` group: + +```shell script +clusterUser="testUser" +k0s user create --groups "system:masters" $clusterUser > ~/clusterUser.kubeconfig +``` +Create the proper roleBinding, to allow the user access to the resources: +```shell script +kubectl create clusterrolebinding $clusterUser-admin-binding --clusterrole=admin --user=$clusterUser +``` \ No newline at end of file