Skip to content

Commit

Permalink
Merge pull request #9280 from olemarkus/no-admin
Browse files Browse the repository at this point in the history
Specify user on export kubecfg
  • Loading branch information
k8s-ci-robot authored Jul 17, 2020
2 parents 5dc8847 + 72fd007 commit 6f3c067
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 59 deletions.
8 changes: 3 additions & 5 deletions cmd/kops/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,14 +613,12 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
updateClusterOptions.Yes = c.Yes
updateClusterOptions.Target = c.Target
updateClusterOptions.OutDir = c.OutDir
updateClusterOptions.admin = true
updateClusterOptions.CreateKubecfg = true

// SSHPublicKey has already been mapped
updateClusterOptions.SSHPublicKey = ""

// No equivalent options:
// updateClusterOptions.MaxTaskDuration = c.MaxTaskDuration
// updateClusterOptions.CreateKubecfg = c.CreateKubecfg

_, err := RunUpdateCluster(ctx, f, cluster.Name, out, updateClusterOptions)
if err != nil {
return err
Expand All @@ -641,7 +639,7 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
fmt.Fprintf(&sb, " * edit your master instance group: kops edit ig --name=%s %s\n", cluster.Name, masters[0].ObjectMeta.Name)
}
fmt.Fprintf(&sb, "\n")
fmt.Fprintf(&sb, "Finally configure your cluster with: kops update cluster --name %s --yes\n", cluster.Name)
fmt.Fprintf(&sb, "Finally configure your cluster with: kops update cluster --name %s --yes --admin\n", cluster.Name)
fmt.Fprintf(&sb, "\n")

_, err := out.Write(sb.Bytes())
Expand Down
34 changes: 23 additions & 11 deletions cmd/kops/export_kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,17 @@ 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 the KUBECONFIG environment variable
if the --kubeconfig flag is not set.
`))

exportKubecfgExample = templates.Examples(i18n.T(`
# export a kubecfg file
kops export kubecfg kubernetes-cluster.example.com
# export a kubeconfig file with the cluster admin user (make sure you keep this user safe!)
kops export kubecfg kubernetes-cluster.example.com --admin
# export using a user already existing in the kubeconfig file
kops export kubecfg kubernetes-cluster.example.com --user my-oidc-user
`))

exportKubecfgShort = i18n.T(`Export kubecfg.`)
Expand All @@ -50,6 +53,8 @@ var (
type ExportKubecfgOptions struct {
KubeConfigPath string
all bool
admin bool
user string
}

func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command {
Expand All @@ -69,8 +74,10 @@ 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().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, "export the cluster admin user and add it to the context")
cmd.Flags().StringVar(&options.user, "user", options.user, "add an existing user to the cluster context")

return cmd
}
Expand All @@ -80,12 +87,17 @@ func RunExportKubecfg(ctx context.Context, f *util.Factory, out io.Writer, optio
if err != nil {
return err
}

var clusterList []*kopsapi.Cluster
if options.all {
if len(args) != 0 {
return fmt.Errorf("Cannot use both --all flag and positional arguments")
return fmt.Errorf("cannot use both --all flag and positional arguments")
}
}
if options.admin && options.user != "" {
return fmt.Errorf("cannot use both --admin and --user")
}

var clusterList []*kopsapi.Cluster
if options.all {
list, err := clientset.ListClusters(ctx, metav1.ListOptions{})
if err != nil {
return err
Expand Down Expand Up @@ -116,7 +128,7 @@ 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, options.user)
if err != nil {
return err
}
Expand Down
32 changes: 28 additions & 4 deletions cmd/kops/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var (

updateClusterExample = templates.Examples(i18n.T(`
# After cluster has been edited or upgraded, configure it with:
kops update cluster k8s-cluster.example.com --yes --state=s3://kops-state-1234 --yes
kops update cluster k8s-cluster.example.com --yes --state=s3://kops-state-1234 --yes --admin
`))

updateClusterShort = i18n.T("Update a cluster.")
Expand All @@ -64,7 +64,10 @@ type UpdateClusterOptions struct {
OutDir string
SSHPublicKey string
RunTasksOptions fi.RunTasksOptions
CreateKubecfg bool

CreateKubecfg bool
admin bool
user string

Phase string

Expand All @@ -78,7 +81,7 @@ func (o *UpdateClusterOptions) InitDefaults() {
o.Target = "direct"
o.SSHPublicKey = ""
o.OutDir = ""
o.CreateKubecfg = true
o.CreateKubecfg = false
o.RunTasksOptions.InitDefaults()
}

Expand Down Expand Up @@ -112,6 +115,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. Implies --create-kube-config")
cmd.Flags().StringVar(&options.user, "user", options.user, "Existing user to add to the cluster context. Implies --create-kube-config")
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"))
Expand All @@ -134,6 +139,24 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string,
isDryrun := false
targetName := c.Target

if c.admin && c.user != "" {
return nil, fmt.Errorf("cannot use both --admin and --user")
}

if c.CreateKubecfg && !c.admin && c.user == "" {
return nil, fmt.Errorf("--create-kube-config requires that either --admin or --user is set")
}

if c.admin && !c.CreateKubecfg {
klog.Info("--admin implies --create-kube-config")
c.CreateKubecfg = true
}

if c.user != "" && !c.CreateKubecfg {
klog.Info("--user implies --create-kube-config")
c.CreateKubecfg = true
}

// direct requires --yes (others do not, because they don't do anything!)
if c.Target == cloudup.TargetDirect {
if !c.Yes {
Expand Down Expand Up @@ -278,10 +301,11 @@ 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, c.user)
if err != nil {
return nil, err
}

err = conf.WriteKubecfg()
if err != nil {
return nil, err
Expand Down
13 changes: 9 additions & 4 deletions docs/cli/kops_export_kubecfg.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Export kubecfg.

### Synopsis

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 the KUBECONFIG environment variable if the --kubeconfig flag is not set.

```
kops export kubecfg CLUSTERNAME [flags]
Expand All @@ -16,16 +16,21 @@ kops export kubecfg CLUSTERNAME [flags]
### Examples

```
# export a kubecfg file
kops export kubecfg kubernetes-cluster.example.com
# export a kubeconfig file with the cluster admin user (make sure you keep this user safe!)
kops export kubecfg kubernetes-cluster.example.com --admin
# export using a user already existing in the kubeconfig file
kops export kubecfg kubernetes-cluster.example.com --user my-oidc-user
```

### Options

```
--admin export the cluster admin user and add it to the context
--all export all clusters from the kops state store
-h, --help help for kubecfg
--kubeconfig string The location of the kubeconfig file to create.
--kubeconfig string the location of the kubeconfig file to create.
--user string add an existing user to the cluster context
```

### Options inherited from parent commands
Expand Down
6 changes: 4 additions & 2 deletions docs/cli/kops_update_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,21 @@ kops update cluster [flags]

```
# After cluster has been edited or upgraded, configure it with:
kops update cluster k8s-cluster.example.com --yes --state=s3://kops-state-1234 --yes
kops update cluster k8s-cluster.example.com --yes --state=s3://kops-state-1234 --yes --admin
```

### Options

```
--create-kube-config Will control automatically creating the kube config file on your local filesystem (default true)
--admin Also export the admin user. Implies --create-kube-config
--create-kube-config Will control automatically creating the kube config file on your local filesystem
-h, --help help for cluster
--lifecycle-overrides strings comma separated list of phase overrides, example: SecurityGroups=Ignore,InternetGateway=ExistsAndWarnIfChanges
--out string Path to write any local output
--phase string Subset of tasks to run: assets, cluster, network, security
--ssh-public-key string SSH public key to use (deprecated: use kops create secret instead)
--target string Target - direct, terraform, cloudformation (default "direct")
--user string Existing user to add to the cluster context. Implies --create-kube-config
-y, --yes Create cloud resources, without --yes update is in dry run mode
```

Expand Down
10 changes: 10 additions & 0 deletions docs/releases/1.19-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

# Significant changes

## Changes to kubernetes config export

Kops will no longer automatically export the kubernetes config on `kops update cluster`. In order to export the config on cluster update, you need to either add the `--user <user>` to reference an existing user, or `--admin` to export the cluster admin user. If neither flag is passed, the kubernetes config will not be modified. This makes it easier to reuse user definitions across clusters should you, for example, use OIDC for authentication.

Similarly, `kops export kubecfg` will also require passing either the `--admin` or `--user` flag if the context does not already exist.

`kops create cluster --yes` exports the admin user along with rest of the cluster config, as is existing behaviour.

## Other significant changes

* On AWS kops now defaults to using launch templates instead of launch configurations.

* Clusters using the Amazon VPC CNI provider now perform an `ec2.DescribeInstanceTypes` call at instance launch time. In large clusters or AWS accounts this may lead to API throttling which could delay node readiness. If this becomes a problem please open a GitHub issue.
Expand Down
46 changes: 28 additions & 18 deletions pkg/kubeconfig/create_kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,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, user string) (*KubeconfigBuilder, error) {
clusterName := cluster.ObjectMeta.Name

master := cluster.Spec.MasterPublicName
Expand Down Expand Up @@ -86,6 +86,7 @@ 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 == "" {
Expand All @@ -103,27 +104,30 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
}
}

{
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()
if admin {
{
cert, key, _, err := keyStore.FindKeypair("kubecfg")
if err != nil {
return nil, err
return nil, fmt.Errorf("error fetching kubecfg keypair: %v", err)
}
} else {
return nil, fmt.Errorf("cannot find kubecfg certificate")
}
if key != nil {
b.ClientKey, err = key.AsBytes()
if err != nil {
return nil, 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 key")
}

}

b.Server = server
Expand Down Expand Up @@ -156,5 +160,11 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se
}
}

if user == "" {
b.User = cluster.ObjectMeta.Name
} else {
b.User = user
}

return b, nil
}
Loading

0 comments on commit 6f3c067

Please sign in to comment.