diff --git a/cmd/kops/export_kubecfg.go b/cmd/kops/export_kubecfg.go index f3939d104fed9..e18abae70d72c 100644 --- a/cmd/kops/export_kubecfg.go +++ b/cmd/kops/export_kubecfg.go @@ -34,10 +34,10 @@ import ( var ( exportKubecfgLong = templates.LongDesc(i18n.T(` - Export a kubecfg file for a cluster from the state store. The configuration - will be saved into a users $HOME/.kube/config file. - To export the kubectl configuration to a specific file set the KUBECONFIG - environment variable.`)) + Export a kubecfg file for a cluster from the state store. By default, the configuration + will be saved into a users $HOME/.kube/config file. Kops will respect KUBECONFIG environment variable + if --kubeconfig flag is not set. + `)) exportKubecfgExample = templates.Examples(i18n.T(` # export a kubecfg file @@ -50,6 +50,8 @@ var ( type ExportKubecfgOptions struct { KubeConfigPath string all bool + admin bool + user string } func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command { @@ -71,6 +73,8 @@ func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command { cmd.Flags().StringVar(&options.KubeConfigPath, "kubeconfig", options.KubeConfigPath, "The location of the kubeconfig file to create.") cmd.Flags().BoolVar(&options.all, "all", options.all, "export all clusters from the kops state store") + cmd.Flags().BoolVar(&options.admin, "admin", options.admin, "also export the admin user") + cmd.Flags().StringVar(&options.user, "user", options.user, "existing user to add to the cluster context") return cmd } @@ -116,7 +120,12 @@ func RunExportKubecfg(ctx context.Context, f *util.Factory, out io.Writer, optio return err } - conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, &commands.CloudDiscoveryStatusStore{}, buildPathOptions(options)) + conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, &commands.CloudDiscoveryStatusStore{}, buildPathOptions(options), options.admin) + if options.admin { + conf.User = cluster.ObjectMeta.Name + } else { + conf.User = options.user + } if err != nil { return err } diff --git a/cmd/kops/update_cluster.go b/cmd/kops/update_cluster.go index a878096b63214..80366501dc924 100644 --- a/cmd/kops/update_cluster.go +++ b/cmd/kops/update_cluster.go @@ -66,7 +66,10 @@ type UpdateClusterOptions struct { OutDir string SSHPublicKey string RunTasksOptions fi.RunTasksOptions - CreateKubecfg bool + + CreateKubecfg bool + admin bool + user string Phase string @@ -116,6 +119,8 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command { cmd.Flags().StringVar(&options.SSHPublicKey, "ssh-public-key", options.SSHPublicKey, "SSH public key to use (deprecated: use kops create secret instead)") cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output") cmd.Flags().BoolVar(&options.CreateKubecfg, "create-kube-config", options.CreateKubecfg, "Will control automatically creating the kube config file on your local filesystem") + cmd.Flags().BoolVar(&options.admin, "admin", options.admin, "also export the admin user") + cmd.Flags().StringVar(&options.user, "user", options.user, "existing user to add to the cluster context") cmd.Flags().StringVar(&options.Phase, "phase", options.Phase, "Subset of tasks to run: "+strings.Join(cloudup.Phases.List(), ", ")) cmd.Flags().StringSliceVar(&options.LifecycleOverrides, "lifecycle-overrides", options.LifecycleOverrides, "comma separated list of phase overrides, example: SecurityGroups=Ignore,InternetGateway=ExistsAndWarnIfChanges") viper.BindPFlag("lifecycle-overrides", cmd.Flags().Lookup("lifecycle-overrides")) @@ -306,10 +311,17 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string, } if kubecfgCert != nil { klog.Infof("Exporting kubecfg for cluster") - conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, &commands.CloudDiscoveryStatusStore{}, clientcmd.NewDefaultPathOptions()) + conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, &commands.CloudDiscoveryStatusStore{}, clientcmd.NewDefaultPathOptions(), c.admin) if err != nil { return nil, err } + + if c.admin { + conf.User = cluster.ObjectMeta.Name + } else { + conf.User = c.user + } + err = conf.WriteKubecfg() if err != nil { return nil, err diff --git a/pkg/kubeconfig/create_kubecfg.go b/pkg/kubeconfig/create_kubecfg.go index 3379c782965c1..41dfdc367dfeb 100644 --- a/pkg/kubeconfig/create_kubecfg.go +++ b/pkg/kubeconfig/create_kubecfg.go @@ -27,7 +27,7 @@ import ( "k8s.io/kops/upup/pkg/fi" ) -func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess) (*KubeconfigBuilder, error) { +func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, status kops.StatusStore, configAccess clientcmd.ConfigAccess, admin bool) (*KubeconfigBuilder, error) { clusterName := cluster.ObjectMeta.Name master := cluster.Spec.MasterPublicName @@ -85,56 +85,57 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se b := NewKubeconfigBuilder(configAccess) b.Context = clusterName + b.Server = server - // add the CA Cert to the kubeconfig only if we didn't specify a SSL cert for the LB - if cluster.Spec.API == nil || cluster.Spec.API.LoadBalancer == nil || cluster.Spec.API.LoadBalancer.SSLCertificate == "" { - cert, _, _, err := keyStore.FindKeypair(fi.CertificateId_CA) - if err != nil { - return nil, fmt.Errorf("error fetching CA keypair: %v", err) - } - if cert != nil { - b.CACert, err = cert.AsBytes() + if admin { + // add the CA Cert to the kubeconfig only if we didn't specify a SSL cert for the LB + if cluster.Spec.API == nil || cluster.Spec.API.LoadBalancer == nil || cluster.Spec.API.LoadBalancer.SSLCertificate == "" { + cert, _, _, err := keyStore.FindKeypair(fi.CertificateId_CA) if err != nil { - return nil, err + return nil, fmt.Errorf("error fetching CA keypair: %v", err) + } + if cert != nil { + b.CACert, err = cert.AsBytes() + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("cannot find CA certificate") } - } else { - return nil, fmt.Errorf("cannot find CA certificate") } - } - { - cert, key, _, err := keyStore.FindKeypair("kubecfg") - if err != nil { - return nil, fmt.Errorf("error fetching kubecfg keypair: %v", err) - } - if cert != nil { - b.ClientCert, err = cert.AsBytes() + { + cert, key, _, err := keyStore.FindKeypair("kubecfg") if err != nil { - return nil, err + return nil, fmt.Errorf("error fetching kubecfg keypair: %v", err) + } + if cert != nil { + b.ClientCert, err = cert.AsBytes() + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("cannot find kubecfg certificate") + } + if key != nil { + b.ClientKey, err = key.AsBytes() + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("cannot find kubecfg key") } - } else { - return nil, fmt.Errorf("cannot find kubecfg certificate") } - if key != nil { - b.ClientKey, err = key.AsBytes() + + if secretStore != nil { + secret, err := secretStore.FindSecret("kube") if err != nil { return nil, err } - } else { - return nil, fmt.Errorf("cannot find kubecfg key") - } - } - - b.Server = server - - if secretStore != nil { - secret, err := secretStore.FindSecret("kube") - if err != nil { - return nil, err - } - if secret != nil { - b.KubeUser = "admin" - b.KubePassword = string(secret.Data) + if secret != nil { + b.KubeUser = "admin" + b.KubePassword = string(secret.Data) + } } } diff --git a/pkg/kubeconfig/kubecfg_builder.go b/pkg/kubeconfig/kubecfg_builder.go index 40ad85be148a0..7d4edb365ab00 100644 --- a/pkg/kubeconfig/kubecfg_builder.go +++ b/pkg/kubeconfig/kubecfg_builder.go @@ -33,6 +33,7 @@ type KubeconfigBuilder struct { Context string Namespace string + User string KubeBearerToken string KubeUser string KubePassword string @@ -116,17 +117,7 @@ func (b *KubeconfigBuilder) WriteKubecfg() error { cluster = clientcmdapi.NewCluster() } cluster.Server = b.Server - - if b.CACert == nil { - // For now, we assume that the cluster has a "real" cert issued by a CA - cluster.InsecureSkipTLSVerify = false - cluster.CertificateAuthority = "" - cluster.CertificateAuthorityData = nil - } else { - cluster.InsecureSkipTLSVerify = false - cluster.CertificateAuthority = "" - cluster.CertificateAuthorityData = b.CACert - } + cluster.CertificateAuthorityData = b.CACert if config.Clusters == nil { config.Clusters = make(map[string]*clientcmdapi.Cluster) @@ -134,7 +125,7 @@ func (b *KubeconfigBuilder) WriteKubecfg() error { config.Clusters[b.Context] = cluster } - { + if b.KubeUser == "admin" { authInfo := config.AuthInfos[b.Context] if authInfo == nil { authInfo = clientcmdapi.NewAuthInfo() @@ -158,6 +149,10 @@ func (b *KubeconfigBuilder) WriteKubecfg() error { config.AuthInfos = make(map[string]*clientcmdapi.AuthInfo) } config.AuthInfos[b.Context] = authInfo + } else if b.User != "" { + if config.AuthInfos[b.User] == nil { + return fmt.Errorf("could not find user %q", b.User) + } } // If we have a bearer token, also create a credential entry with basic auth @@ -186,7 +181,9 @@ func (b *KubeconfigBuilder) WriteKubecfg() error { } context.Cluster = b.Context - context.AuthInfo = b.Context + if b.User != "" { + context.AuthInfo = b.User + } if b.Namespace != "" { context.Namespace = b.Namespace