diff --git a/README.md b/README.md index 490d4b86..15c5d266 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ subjects: Setup `kubectl` to authenticate with your identity provider. ```sh -kubectl config set-credentials CLUSTER_NAME \ +kubectl config set-credentials NAME \ --auth-provider oidc \ --auth-provider-arg idp-issuer-url=https://accounts.google.com \ --auth-provider-arg client-id=YOUR_CLIENT_ID.apps.googleusercontent.com \ @@ -170,7 +170,7 @@ subjects: Setup `kubectl` to authenticate with your identity provider. ```sh -kubectl config set-credentials CLUSTER_NAME \ +kubectl config set-credentials NAME \ --auth-provider oidc \ --auth-provider-arg idp-issuer-url=https://keycloak.example.com/auth/realms/YOUR_REALM \ --auth-provider-arg client-id=kubernetes \ diff --git a/cli/cli.go b/cli/cli.go index 039d8528..9e136a9d 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -37,30 +37,33 @@ type CLI struct { func (c *CLI) ExpandKubeConfig() (string, error) { d, err := homedir.Expand(c.KubeConfig) if err != nil { - return "", fmt.Errorf("Could not expand %s", c.KubeConfig) + return "", fmt.Errorf("Could not expand %s: %s", c.KubeConfig, err) } return d, nil } // Run performs this command. func (c *CLI) Run(ctx context.Context) error { + log.Printf("Reading %s", c.KubeConfig) path, err := c.ExpandKubeConfig() if err != nil { return err } - log.Printf("Reading %s", path) cfg, err := kubeconfig.Read(path) if err != nil { - return fmt.Errorf("Could not load kubeconfig: %s", err) + return fmt.Errorf("Could not read kubeconfig: %s", err) } - log.Printf("Using current context: %s", cfg.CurrentContext) - authInfo := kubeconfig.FindCurrentAuthInfo(cfg) - if authInfo == nil { - return fmt.Errorf("Could not find current context: %s", cfg.CurrentContext) - } - authProvider, err := kubeconfig.FindOIDCAuthProvider(authInfo) + log.Printf("Using current-context: %s", cfg.CurrentContext) + authProvider, err := kubeconfig.FindOIDCAuthProvider(cfg) if err != nil { - return fmt.Errorf("Could not find auth-provider: %s", err) + return fmt.Errorf(`Could not find OIDC configuration in kubeconfig: %s + Did you setup kubectl for OIDC authentication? + kubectl config set-credentials %s \ + --auth-provider oidc \ + --auth-provider-arg idp-issuer-url=https://issuer.example.com \ + --auth-provider-arg client-id=YOUR_CLIENT_ID \ + --auth-provider-arg client-secret=YOUR_CLIENT_SECRET`, + err, cfg.CurrentContext) } tlsConfig, err := c.tlsConfig(authProvider) if err != nil { @@ -77,12 +80,12 @@ func (c *CLI) Run(ctx context.Context) error { } token, err := authConfig.GetTokenSet(ctx) if err != nil { - return fmt.Errorf("Authentication error: %s", err) + return fmt.Errorf("Could not get token from OIDC provider: %s", err) } authProvider.SetIDToken(token.IDToken) authProvider.SetRefreshToken(token.RefreshToken) kubeconfig.Write(cfg, path) - log.Printf("Updated %s", path) + log.Printf("Updated %s", c.KubeConfig) return nil } diff --git a/cli/tls.go b/cli/tls.go index ee7cc78e..522e69cc 100644 --- a/cli/tls.go +++ b/cli/tls.go @@ -13,25 +13,25 @@ import ( func (c *CLI) tlsConfig(authProvider *kubeconfig.OIDCAuthProvider) (*tls.Config, error) { p := x509.NewCertPool() - if authProvider.IDPCertificateAuthority() != "" { - b, err := ioutil.ReadFile(authProvider.IDPCertificateAuthority()) + if ca := authProvider.IDPCertificateAuthority(); ca != "" { + b, err := ioutil.ReadFile(ca) if err != nil { - return nil, fmt.Errorf("Could not read idp-certificate-authority: %s", err) + return nil, fmt.Errorf("Could not read %s: %s", ca, err) } if p.AppendCertsFromPEM(b) != true { - return nil, fmt.Errorf("Could not load CA certificate from idp-certificate-authority: %s", err) + return nil, fmt.Errorf("Could not append CA certificate from %s", ca) } - log.Printf("Using CA certificate: %s", authProvider.IDPCertificateAuthority()) + log.Printf("Using CA certificate: %s", ca) } - if authProvider.IDPCertificateAuthorityData() != "" { - b, err := base64.StdEncoding.DecodeString(authProvider.IDPCertificateAuthorityData()) + if ca := authProvider.IDPCertificateAuthorityData(); ca != "" { + b, err := base64.StdEncoding.DecodeString(ca) if err != nil { return nil, fmt.Errorf("Could not decode idp-certificate-authority-data: %s", err) } if p.AppendCertsFromPEM(b) != true { - return nil, fmt.Errorf("Could not load CA certificate from idp-certificate-authority-data: %s", err) + return nil, fmt.Errorf("Could not append CA certificate from idp-certificate-authority-data") } - log.Printf("Using CA certificate of idp-certificate-authority-data") + log.Printf("Using CA certificate: idp-certificate-authority-data") } cfg := &tls.Config{InsecureSkipVerify: c.SkipTLSVerify} diff --git a/kubeconfig/auth.go b/kubeconfig/auth.go index f63d7b37..616aad95 100644 --- a/kubeconfig/auth.go +++ b/kubeconfig/auth.go @@ -7,23 +7,23 @@ import ( "k8s.io/client-go/tools/clientcmd/api" ) -// FindCurrentAuthInfo returns the authInfo of current context. -// If the current context does not exist, this returns nil. -func FindCurrentAuthInfo(config *api.Config) *api.AuthInfo { +// FindOIDCAuthProvider returns the current OIDC authProvider. +// If the context, auth-info or auth-provider does not exist, this returns an error. +// If auth-provider is not "oidc", this returns an error. +func FindOIDCAuthProvider(config *api.Config) (*OIDCAuthProvider, error) { context := config.Contexts[config.CurrentContext] if context == nil { - return nil + return nil, fmt.Errorf("context %s does not exist", config.CurrentContext) + } + authInfo := config.AuthInfos[context.AuthInfo] + if authInfo == nil { + return nil, fmt.Errorf("auth-info %s does not exist", context.AuthInfo) } - return config.AuthInfos[context.AuthInfo] -} - -// FindOIDCAuthProvider returns the OIDC authProvider. -func FindOIDCAuthProvider(authInfo *api.AuthInfo) (*OIDCAuthProvider, error) { if authInfo.AuthProvider == nil { - return nil, fmt.Errorf("auth-provider is not set, did you setup kubectl as listed here: https://github.com/int128/kubelogin") + return nil, fmt.Errorf("auth-provider is not set") } if authInfo.AuthProvider.Name != "oidc" { - return nil, fmt.Errorf("auth-provider `%s` is not supported", authInfo.AuthProvider.Name) + return nil, fmt.Errorf("auth-provider name is %s but must be oidc", authInfo.AuthProvider.Name) } return (*OIDCAuthProvider)(authInfo.AuthProvider), nil } diff --git a/kubeconfig/kubeconfig.go b/kubeconfig/kubeconfig.go index 3b83f2a1..ec8238b3 100644 --- a/kubeconfig/kubeconfig.go +++ b/kubeconfig/kubeconfig.go @@ -1,19 +1,13 @@ package kubeconfig import ( - "fmt" - "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" ) // Read parses the file and returns the Config. func Read(path string) (*api.Config, error) { - config, err := clientcmd.LoadFromFile(path) - if err != nil { - return nil, fmt.Errorf("Could not load kubeconfig from %s: %s", path, err) - } - return config, nil + return clientcmd.LoadFromFile(path) } // Write writes the config to the file. diff --git a/main.go b/main.go index e89499d9..15c31859 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,6 @@ func main() { } ctx := context.Background() if err := c.Run(ctx); err != nil { - log.Fatal(err) + log.Fatalf("Error: %s", err) } }