cmd

package
v0.0.0-...-9c00b4c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2022 License: MIT Imports: 28 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var RootCmd = &cobra.Command{
	Use:   "kube-config",
	Short: "Configure a kubeconfig for Kubernetes Clusters that have Dex as an IDP",
	Long: `kube-config is a method of authenticating to a Kubernetes cluster which uses Dex an IDP.
	
The tool will authenticate you using your credentials provider, and grab a token.
It will also generate you a Kubernetes configuration file based on your login credentials.`,

	Run: func(cmd *cobra.Command, args []string) {

		if debug {

			if a.client == nil {
				a.client = &http.Client{
					Transport: debugTransport{http.DefaultTransport},
				}
			} else {
				a.client.Transport = debugTransport{a.client.Transport}
			}
		}

		tlsConfig := &tls.Config{
			InsecureSkipVerify: insecure,
		}

		if a.client == nil {
			c := cleanhttp.DefaultClient()
			t := cleanhttp.DefaultTransport()
			t.TLSClientConfig = tlsConfig
			c.Transport = t
			a.client = c
		}

		err := viper.UnmarshalKey("tiers", &tiers)
		if err != nil {
			log.Fatalf("Failed to unmarshal key for given tiers: %v", tiers)
		}

		if listTiers {

			var entry []string

			log.Info("Outputting available tiers")

			table := tablewriter.NewWriter(os.Stdout)
			table.SetHeader([]string{"Name", "Issuer", "CAServerName"})

			for _, v := range tiers {
				entry = append(entry, v.Name)
				entry = append(entry, v.Issuer)
				entry = append(entry, v.CAServerName)
				table.Append(entry)
				entry = entry[:0]
			}

			table.Render()

			os.Exit(0)

		}

		for _, i := range tiers {
			if i.Name == tier {
				issuerURL = i.Issuer
				if i.CAServerName != "" {
					caservername = i.CAServerName
				}

				log.Debug("Using Issuer URL: ", issuerURL)
			}
		}

		ctx := oidc.ClientContext(context.Background(), a.client)
		provider, err := oidc.NewProvider(ctx, issuerURL)
		if err != nil {
			log.Fatalf("Failed to query provider %q: %v", issuerURL, err)
		}

		var s struct {
			// What scopes does a provider support?
			//
			// See: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
			ScopesSupported []string `json:"scopes_supported"`
		}

		if err := provider.Claims(&s); err != nil {
			log.Fatalf("Failed to parse provider scopes_supported: %v", err)
		}

		if len(s.ScopesSupported) == 0 {

			a.offlineAsScope = true
		} else {

			a.offlineAsScope = func() bool {
				for _, scope := range s.ScopesSupported {
					if scope == oidc.ScopeOfflineAccess {
						return true
					}
				}
				return false
			}()

		}

		a.provider = provider
		a.verifier = provider.Verifier(&oidc.Config{ClientID: a.clientID})
		a.state, err = generateState()
		a.tokenRetrieved = make(chan int, 1)

		if err != nil {
			log.Fatal("Error generating state: ", err)
		}

		fileHandle := os.Stdout

		if outputFilePath != "" {
			var ok bool

			log.Debug(outputFilePath)

			if _, err := os.Stat(outputFilePath); os.IsNotExist(err) {
				ok = prompt.Confirm("The kube-config directory doesn't exist at %s - Would you like to create it?: (y/n) ", outputFilePath)
				if ok {
					err := os.MkdirAll(outputFilePath, 0700)
					if err != nil {
						log.Fatalf("Error creating directory: %s", err)
					}
				} else {
					log.Fatalf("Cannot continue, please create directory %s", outputFilePath)
				}
			}

			fileHandle, err = os.Create(outputFilePath + "/" + tier + "-config.yml")
			if err != nil {
				log.Fatalf("Error creating kubeconfig: %v", err)
			}
		}

		userName = viper.GetString("username")
		a.clientSecret = viper.GetString("client-secret")

		err = viper.UnmarshalKey("clusters", &clusters)

		if err != nil {
			log.Fatalf("Error reading datacenters: %v", err)
		}

		if clusters == nil {
			log.Fatal("No clusters specified in config file")
		}

		if userName == "" {
			log.Fatal("Please specify a username to login with")
		}

		if a.clientSecret == "" {
			log.Fatal("Client secret must be specified in config file")
		}

		tierClusters := clusters[:0]

		for _, c := range clusters {
			if c.Tier == tier {
				tierClusters = append(tierClusters, c)
			}
		}

		kubeConfig, err := NewKubeConfig(cluster, tierClusters, userName, namespace, caservername, fileHandle, a.clientID, issuerURL, a.clientSecret)

		if err != nil {
			log.Warn("Error generating KubeConfig: ", err)
		}

		a.kubeconfig = kubeConfig

		srv := startHTTPServer(&a, listen)

		open.Run(listen)

		<-a.tokenRetrieved

		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		if err := srv.Shutdown(ctx); err != nil {
			log.Info("Error shutting down the server gracefully - this isn't usually an issue: ", err)
		}

		log.Infof("Your kubeconfig has been written to %s/%s-config.yml", outputFilePath, tier)

		kubeconfig := os.Getenv("KUBECONFIG")

		kc := strings.Split(kubeconfig, ":")

		valid := stringInSlice(outputFilePath+"/"+tier+"-config.yml", kc)

		if !valid {
			fmt.Printf("\nYou have not correctly configured your KUBECONFIG environment variable\nThe file %s/%s-config.yml needs to be added\n", outputFilePath, tier)
			fmt.Print("Please run the following command:\n\n")
			fmt.Printf("export KUBECONFIG=$HOME/.kube/config; for i in %s/*.yml; do export KUBECONFIG=$KUBECONFIG:$i; done\n\n", outputFilePath)
		}

	},
}

RootCmd represents the base command when called without any subcommands

View Source
var Version string

Version string for the version command

Functions

func Execute

func Execute(version string)

Execute adds all child commands to the root command sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.

func GetCertificate

func GetCertificate(serverName string, address string) string

GetCertificate fetches remote certificate from the given serverName and address.

Types

type Clusters

type Clusters struct {
	Name         string
	Address      string
	CAServerName string
	Certificate  string
	Tier         string
}

Clusters struct represents type of Cluster.

type KubeConfig

type KubeConfig struct {
	Cluster      string
	Clusters     []Clusters
	Username     string
	NS           string
	CAServerName string

	Output       io.ReadWriteCloser
	ClientID     string
	Issuer       string
	ClientSecret string
	Tier         string
	// contains filtered or unexported fields
}

KubeConfig holds the information necessary to generate a Kubernetes configuration file which icludes the server's CA, the api url and where to write the file to.

func NewKubeConfig

func NewKubeConfig(cluster string, clusters []Clusters, username string, namespace string, caservername string, output io.ReadWriteCloser, clientID string, issuer string, clientSecret string) (*KubeConfig, error)

NewKubeConfig returns an initialized KubeConfig struct.

func (*KubeConfig) Generate

func (k *KubeConfig) Generate(token string, refreshToken string) error

Generate executes the writing of the config to the appropriate location (os.Stdout, os.File, etc...).

type Tiers

type Tiers struct {
	Name         string
	Issuer       string
	CAServerName string
}

Tiers struct represents type of Tier.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL