Skip to content

Commit

Permalink
Support authentication helper for kubectl
Browse files Browse the repository at this point in the history
We create a simple exec plugin command which can create and renew
short-lived admin credentials on the fly, essentially leveraging the
security of the underlying cloud credentials.

Co-authored-by: John Gardiner Myers <[email protected]>
  • Loading branch information
justinsb and johngmyers committed Aug 28, 2020
1 parent 3f079cd commit 03906b3
Show file tree
Hide file tree
Showing 15 changed files with 452 additions and 8 deletions.
1 change: 1 addition & 0 deletions cmd/kops/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ go_library(
"//pkg/client/simple:go_default_library",
"//pkg/cloudinstances:go_default_library",
"//pkg/commands:go_default_library",
"//pkg/commands/commandutils:go_default_library",
"//pkg/dump:go_default_library",
"//pkg/edit:go_default_library",
"//pkg/featureflag:go_default_library",
Expand Down
16 changes: 15 additions & 1 deletion cmd/kops/export_kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ type ExportKubecfgOptions struct {
admin time.Duration
user string
internal bool

// UseKopsAuthenticationPlugin controls whether we should use the kops auth helper instead of a static credential
UseKopsAuthenticationPlugin bool
}

func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command {
Expand All @@ -85,6 +88,7 @@ func NewCmdExportKubecfg(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().Lookup("admin").NoOptDefVal = kubeconfig.DefaultKubecfgAdminLifetime.String()
cmd.Flags().StringVar(&options.user, "user", options.user, "add an existing user to the cluster context")
cmd.Flags().BoolVar(&options.internal, "internal", options.internal, "use the cluster's internal DNS name")
cmd.Flags().BoolVar(&options.UseKopsAuthenticationPlugin, "auth-plugin", options.UseKopsAuthenticationPlugin, "install the kops authentication plugin")

return cmd
}
Expand Down Expand Up @@ -135,7 +139,17 @@ 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), options.admin, options.user, options.internal)
conf, err := kubeconfig.BuildKubecfg(
cluster,
keyStore,
secretStore,
&commands.CloudDiscoveryStatusStore{},
buildPathOptions(options),
options.admin,
options.user,
options.internal,
f.KopsStateStore(),
options.UseKopsAuthenticationPlugin)
if err != nil {
return err
}
Expand Down
6 changes: 2 additions & 4 deletions cmd/kops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ limitations under the License.
package main // import "k8s.io/kops/cmd/kops"

import (
"fmt"
"os"
"k8s.io/kops/pkg/commands/commandutils"
)

func main() {
Expand All @@ -28,6 +27,5 @@ func main() {
// exitWithError will terminate execution with an error result
// It prints the error to stderr and exits with a non-zero exit code
func exitWithError(err error) {
fmt.Fprintf(os.Stderr, "\n%v\n", err)
os.Exit(1)
commandutils.ExitWithError(err)
}
2 changes: 2 additions & 0 deletions cmd/kops/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"k8s.io/kops/cmd/kops/util"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/commands"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
Expand Down Expand Up @@ -143,6 +144,7 @@ func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command {
cmd.AddCommand(NewCmdEdit(f, out))
cmd.AddCommand(NewCmdExport(f, out))
cmd.AddCommand(NewCmdGet(f, out))
cmd.AddCommand(commands.NewCmdHelpers(f, out))
cmd.AddCommand(NewCmdUpdate(f, out))
cmd.AddCommand(NewCmdReplace(f, out))
cmd.AddCommand(NewCmdRollingUpdate(f, out))
Expand Down
14 changes: 13 additions & 1 deletion cmd/kops/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,19 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string,
firstRun = !hasKubecfg

klog.Infof("Exporting kubecfg for cluster")
conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, &commands.CloudDiscoveryStatusStore{}, clientcmd.NewDefaultPathOptions(), c.admin, c.user, c.internal)
// TODO: Another flag?
useKopsAuthenticationPlugin := false
conf, err := kubeconfig.BuildKubecfg(
cluster,
keyStore,
secretStore,
&commands.CloudDiscoveryStatusStore{},
clientcmd.NewDefaultPathOptions(),
c.admin,
c.user,
c.internal,
f.KopsStateStore(),
useKopsAuthenticationPlugin)
if err != nil {
return nil, err
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/kops/util/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,8 @@ func (f *Factory) Clientset() (simple.Clientset, error) {

return f.clientset, nil
}

// KopsStateStore returns the configured KOPS_STATE_STORE in use
func (f *Factory) KopsStateStore() string {
return f.options.RegistryPath
}
2 changes: 2 additions & 0 deletions hack/.packages
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ k8s.io/kops/pkg/client/simple/api
k8s.io/kops/pkg/client/simple/vfsclientset
k8s.io/kops/pkg/cloudinstances
k8s.io/kops/pkg/commands
k8s.io/kops/pkg/commands/commandutils
k8s.io/kops/pkg/commands/helpers
k8s.io/kops/pkg/configbuilder
k8s.io/kops/pkg/diff
k8s.io/kops/pkg/dns
Expand Down
4 changes: 4 additions & 0 deletions pkg/commands/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"helpers.go",
"helpers_readwrite.go",
"set_cluster.go",
"status_discovery.go",
Expand All @@ -17,6 +18,7 @@ go_library(
"//pkg/apis/kops/validation:go_default_library",
"//pkg/assets:go_default_library",
"//pkg/client/simple:go_default_library",
"//pkg/commands/helpers:go_default_library",
"//pkg/featureflag:go_default_library",
"//pkg/resources/digitalocean:go_default_library",
"//upup/pkg/fi:go_default_library",
Expand All @@ -30,6 +32,8 @@ go_library(
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/kubectl/pkg/util/i18n:go_default_library",
"//vendor/k8s.io/kubectl/pkg/util/templates:go_default_library",
],
)

Expand Down
8 changes: 8 additions & 0 deletions pkg/commands/commandutils/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["exit.go"],
importpath = "k8s.io/kops/pkg/commands/commandutils",
visibility = ["//visibility:public"],
)
29 changes: 29 additions & 0 deletions pkg/commands/commandutils/exit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commandutils

import (
"fmt"
"os"
)

// ExitWithError will terminate execution with an error result
// It prints the error to stderr and exits with a non-zero exit code
func ExitWithError(err error) {
fmt.Fprintf(os.Stderr, "\n%v\n", err)
os.Exit(1)
}
50 changes: 50 additions & 0 deletions pkg/commands/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commands

import (
"io"

"github.com/spf13/cobra"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/commands/helpers"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)

var (
helpersLong = templates.LongDesc(i18n.T(`
Commands intended for integration with other systems.`))

helpersShort = i18n.T(`Commands for use with other systems.`)
)

// NewCmdHelpers builds the cobra command tree for the `helpers` subcommand
func NewCmdHelpers(f *util.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "helpers",
Short: helpersShort,
Long: helpersLong,

// We hide the command, as it is intended for internal usage
Hidden: true,
}

cmd.AddCommand(helpers.NewCmdHelperKubectlAuth(f, out))

return cmd
}
19 changes: 19 additions & 0 deletions pkg/commands/helpers/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["kubectl_auth.go"],
importpath = "k8s.io/kops/pkg/commands/helpers",
visibility = ["//visibility:public"],
deps = [
"//cmd/kops/util:go_default_library",
"//pkg/commands/commandutils:go_default_library",
"//pkg/pki:go_default_library",
"//pkg/rbac:go_default_library",
"//upup/pkg/fi:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/client-go/util/homedir:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
"//vendor/k8s.io/kubectl/pkg/util/i18n:go_default_library",
],
)
Loading

0 comments on commit 03906b3

Please sign in to comment.