mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Add client auth plugin framework for kubectl with GCP auth plugin.
This commit is contained in:
		@@ -30,6 +30,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
			
		||||
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/crypto"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/version"
 | 
			
		||||
@@ -65,6 +66,9 @@ type Config struct {
 | 
			
		||||
	// Impersonate is the username that this RESTClient will impersonate
 | 
			
		||||
	Impersonate string
 | 
			
		||||
 | 
			
		||||
	// Server requires plugin-specified authentication.
 | 
			
		||||
	AuthProvider *clientcmdapi.AuthProviderConfig
 | 
			
		||||
 | 
			
		||||
	// TLSClientConfig contains settings to enable transport layer security
 | 
			
		||||
	TLSClientConfig
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								pkg/client/restclient/plugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								pkg/client/restclient/plugin.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 restclient
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
 | 
			
		||||
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthProvider interface {
 | 
			
		||||
	// WrapTransport allows the plugin to create a modified RoundTripper that
 | 
			
		||||
	// attaches authorization headers (or other info) to requests.
 | 
			
		||||
	WrapTransport(http.RoundTripper) http.RoundTripper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Factory func() (AuthProvider, error)
 | 
			
		||||
 | 
			
		||||
// All registered auth provider plugins.
 | 
			
		||||
var pluginsLock sync.Mutex
 | 
			
		||||
var plugins = make(map[string]Factory)
 | 
			
		||||
 | 
			
		||||
func RegisterAuthProviderPlugin(name string, plugin Factory) error {
 | 
			
		||||
	pluginsLock.Lock()
 | 
			
		||||
	defer pluginsLock.Unlock()
 | 
			
		||||
	if _, found := plugins[name]; found {
 | 
			
		||||
		return fmt.Errorf("Auth Provider Plugin %q was registered twice", name)
 | 
			
		||||
	}
 | 
			
		||||
	glog.V(4).Infof("Registered Auth Provider Plugin %q", name)
 | 
			
		||||
	plugins[name] = plugin
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetAuthProvider(apc *clientcmdapi.AuthProviderConfig) (AuthProvider, error) {
 | 
			
		||||
	pluginsLock.Lock()
 | 
			
		||||
	defer pluginsLock.Unlock()
 | 
			
		||||
	p, ok := plugins[apc.Name]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, fmt.Errorf("No Auth Provider found for name %q", apc.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return p()
 | 
			
		||||
}
 | 
			
		||||
@@ -26,14 +26,22 @@ import (
 | 
			
		||||
// TLSConfigFor returns a tls.Config that will provide the transport level security defined
 | 
			
		||||
// by the provided Config. Will return nil if no transport level security is requested.
 | 
			
		||||
func TLSConfigFor(config *Config) (*tls.Config, error) {
 | 
			
		||||
	return transport.TLSConfigFor(config.transportConfig())
 | 
			
		||||
	cfg, err := config.transportConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return transport.TLSConfigFor(cfg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TransportFor returns an http.RoundTripper that will provide the authentication
 | 
			
		||||
// or transport level security defined by the provided Config. Will return the
 | 
			
		||||
// default http.DefaultTransport if no special case behavior is needed.
 | 
			
		||||
func TransportFor(config *Config) (http.RoundTripper, error) {
 | 
			
		||||
	return transport.New(config.transportConfig())
 | 
			
		||||
	cfg, err := config.transportConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return transport.New(cfg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTTPWrappersForConfig wraps a round tripper with any relevant layered behavior from the
 | 
			
		||||
@@ -41,15 +49,34 @@ func TransportFor(config *Config) (http.RoundTripper, error) {
 | 
			
		||||
// the underlying connection (like WebSocket or HTTP2 clients). Pure HTTP clients should use
 | 
			
		||||
// the higher level TransportFor or RESTClientFor methods.
 | 
			
		||||
func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) {
 | 
			
		||||
	return transport.HTTPWrappersForConfig(config.transportConfig(), rt)
 | 
			
		||||
	cfg, err := config.transportConfig()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return transport.HTTPWrappersForConfig(cfg, rt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// transportConfig converts a client config to an appropriate transport config.
 | 
			
		||||
func (c *Config) transportConfig() *transport.Config {
 | 
			
		||||
func (c *Config) transportConfig() (*transport.Config, error) {
 | 
			
		||||
	wt := c.WrapTransport
 | 
			
		||||
	if c.AuthProvider != nil {
 | 
			
		||||
		provider, err := GetAuthProvider(c.AuthProvider)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if wt != nil {
 | 
			
		||||
			previousWT := wt
 | 
			
		||||
			wt = func(rt http.RoundTripper) http.RoundTripper {
 | 
			
		||||
				return provider.WrapTransport(previousWT(rt))
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			wt = provider.WrapTransport
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &transport.Config{
 | 
			
		||||
		UserAgent:     c.UserAgent,
 | 
			
		||||
		Transport:     c.Transport,
 | 
			
		||||
		WrapTransport: c.WrapTransport,
 | 
			
		||||
		WrapTransport: wt,
 | 
			
		||||
		TLS: transport.TLSConfig{
 | 
			
		||||
			CAFile:   c.CAFile,
 | 
			
		||||
			CAData:   c.CAData,
 | 
			
		||||
@@ -63,5 +90,5 @@ func (c *Config) transportConfig() *transport.Config {
 | 
			
		||||
		Password:    c.Password,
 | 
			
		||||
		BearerToken: c.BearerToken,
 | 
			
		||||
		Impersonate: c.Impersonate,
 | 
			
		||||
	}
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										171
									
								
								pkg/client/restclient/transport_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								pkg/client/restclient/transport_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 restclient
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTransportConfigAuthPlugins(t *testing.T) {
 | 
			
		||||
	if err := RegisterAuthProviderPlugin("pluginA", pluginAProvider); err != nil {
 | 
			
		||||
		t.Errorf("Unexpected error: failed to register pluginA: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := RegisterAuthProviderPlugin("pluginB", pluginBProvider); err != nil {
 | 
			
		||||
		t.Errorf("Unexpected error: failed to register pluginB: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := RegisterAuthProviderPlugin("pluginFail", pluginFailProvider); err != nil {
 | 
			
		||||
		t.Errorf("Unexpected error: failed to register pluginFail: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		useWrapTransport bool
 | 
			
		||||
		plugin           string
 | 
			
		||||
		expectErr        bool
 | 
			
		||||
		expectPluginA    bool
 | 
			
		||||
		expectPluginB    bool
 | 
			
		||||
	}{
 | 
			
		||||
		{false, "", false, false, false},
 | 
			
		||||
		{false, "pluginA", false, true, false},
 | 
			
		||||
		{false, "pluginB", false, false, true},
 | 
			
		||||
		{false, "pluginFail", true, false, false},
 | 
			
		||||
		{false, "pluginUnknown", true, false, false},
 | 
			
		||||
	}
 | 
			
		||||
	for i, tc := range testCases {
 | 
			
		||||
		c := Config{}
 | 
			
		||||
		if tc.useWrapTransport {
 | 
			
		||||
			// Specify an existing WrapTransport in the config to make sure that
 | 
			
		||||
			// plugins play nicely.
 | 
			
		||||
			c.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
 | 
			
		||||
				return &wrapTransport{rt}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if len(tc.plugin) != 0 {
 | 
			
		||||
			c.AuthProvider = &clientcmdapi.AuthProviderConfig{Name: tc.plugin}
 | 
			
		||||
		}
 | 
			
		||||
		tConfig, err := c.transportConfig()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Unknown/bad plugins are expected to fail here.
 | 
			
		||||
			if !tc.expectErr {
 | 
			
		||||
				t.Errorf("%d. Did not expect errors loading Auth Plugin: %q. Got: %v", i, tc.plugin, err)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		var fullyWrappedTransport http.RoundTripper
 | 
			
		||||
		fullyWrappedTransport = &emptyTransport{}
 | 
			
		||||
		if tConfig.WrapTransport != nil {
 | 
			
		||||
			fullyWrappedTransport = tConfig.WrapTransport(&emptyTransport{})
 | 
			
		||||
		}
 | 
			
		||||
		res, err := fullyWrappedTransport.RoundTrip(&http.Request{})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("%d. Unexpected error in RoundTrip: %v", i, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		hasWrapTransport := res.Header.Get("wrapTransport") == "Y"
 | 
			
		||||
		hasPluginA := res.Header.Get("pluginA") == "Y"
 | 
			
		||||
		hasPluginB := res.Header.Get("pluginB") == "Y"
 | 
			
		||||
		if hasWrapTransport != tc.useWrapTransport {
 | 
			
		||||
			t.Errorf("%d. Expected Existing config.WrapTransport: %t; Got: %t", i, tc.useWrapTransport, hasWrapTransport)
 | 
			
		||||
		}
 | 
			
		||||
		if hasPluginA != tc.expectPluginA {
 | 
			
		||||
			t.Errorf("%d. Expected Plugin A: %t; Got: %t", i, tc.expectPluginA, hasPluginA)
 | 
			
		||||
		}
 | 
			
		||||
		if hasPluginB != tc.expectPluginB {
 | 
			
		||||
			t.Errorf("%d. Expected Plugin B: %t; Got: %t", i, tc.expectPluginB, hasPluginB)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// emptyTransport provides an empty http.Response with an initialized header
 | 
			
		||||
// to allow wrapping RoundTrippers to set header values.
 | 
			
		||||
type emptyTransport struct{}
 | 
			
		||||
 | 
			
		||||
func (*emptyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
			
		||||
	res := &http.Response{
 | 
			
		||||
		Header: make(map[string][]string),
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wrapTransport sets "wrapTransport" = "Y" on the response.
 | 
			
		||||
type wrapTransport struct {
 | 
			
		||||
	rt http.RoundTripper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *wrapTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
			
		||||
	res, err := w.rt.RoundTrip(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	res.Header.Add("wrapTransport", "Y")
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wrapTransportA sets "pluginA" = "Y" on the response.
 | 
			
		||||
type wrapTransportA struct {
 | 
			
		||||
	rt http.RoundTripper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *wrapTransportA) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
			
		||||
	res, err := w.rt.RoundTrip(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	res.Header.Add("pluginA", "Y")
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pluginA struct{}
 | 
			
		||||
 | 
			
		||||
func (*pluginA) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
			
		||||
	return &wrapTransportA{rt}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pluginAProvider() (AuthProvider, error) {
 | 
			
		||||
	return &pluginA{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wrapTransportB sets "pluginB" = "Y" on the response.
 | 
			
		||||
type wrapTransportB struct {
 | 
			
		||||
	rt http.RoundTripper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *wrapTransportB) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
			
		||||
	res, err := w.rt.RoundTrip(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	res.Header.Add("pluginB", "Y")
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pluginB struct{}
 | 
			
		||||
 | 
			
		||||
func (*pluginB) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
			
		||||
	return &wrapTransportB{rt}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pluginBProvider() (AuthProvider, error) {
 | 
			
		||||
	return &pluginB{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pluginFailProvider simulates a registered AuthPlugin that fails to load.
 | 
			
		||||
func pluginFailProvider() (AuthProvider, error) {
 | 
			
		||||
	return nil, fmt.Errorf("Failed to load AuthProvider")
 | 
			
		||||
}
 | 
			
		||||
@@ -94,6 +94,8 @@ type AuthInfo struct {
 | 
			
		||||
	Username string `json:"username,omitempty"`
 | 
			
		||||
	// Password is the password for basic authentication to the kubernetes cluster.
 | 
			
		||||
	Password string `json:"password,omitempty"`
 | 
			
		||||
	// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
 | 
			
		||||
	AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"`
 | 
			
		||||
	// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
 | 
			
		||||
	Extensions map[string]runtime.Object `json:"extensions,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
@@ -112,6 +114,11 @@ type Context struct {
 | 
			
		||||
	Extensions map[string]runtime.Object `json:"extensions,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthProviderConfig holds the configuration for a specified auth provider.
 | 
			
		||||
type AuthProviderConfig struct {
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConfig is a convenience function that returns a new Config object with non-nil maps
 | 
			
		||||
func NewConfig() *Config {
 | 
			
		||||
	return &Config{
 | 
			
		||||
 
 | 
			
		||||
@@ -58,14 +58,17 @@ func Example_ofOptionsConfig() {
 | 
			
		||||
	defaultConfig.AuthInfos["red-mage-via-token"] = &AuthInfo{
 | 
			
		||||
		Token: "my-secret-token",
 | 
			
		||||
	}
 | 
			
		||||
	defaultConfig.AuthInfos["black-mage-via-auth-provider"] = &AuthInfo{
 | 
			
		||||
		AuthProvider: &AuthProviderConfig{Name: "gcp"},
 | 
			
		||||
	}
 | 
			
		||||
	defaultConfig.Contexts["bravo-as-black-mage"] = &Context{
 | 
			
		||||
		Cluster:   "bravo",
 | 
			
		||||
		AuthInfo:  "black-mage-via-file",
 | 
			
		||||
		AuthInfo:  "black-mage-via-auth-provider",
 | 
			
		||||
		Namespace: "yankee",
 | 
			
		||||
	}
 | 
			
		||||
	defaultConfig.Contexts["alfa-as-black-mage"] = &Context{
 | 
			
		||||
		Cluster:   "alfa",
 | 
			
		||||
		AuthInfo:  "black-mage-via-file",
 | 
			
		||||
		AuthInfo:  "black-mage-via-auth-provider",
 | 
			
		||||
		Namespace: "zulu",
 | 
			
		||||
	}
 | 
			
		||||
	defaultConfig.Contexts["alfa-as-white-mage"] = &Context{
 | 
			
		||||
@@ -95,7 +98,7 @@ func Example_ofOptionsConfig() {
 | 
			
		||||
	//     LocationOfOrigin: ""
 | 
			
		||||
	//     cluster: alfa
 | 
			
		||||
	//     namespace: zulu
 | 
			
		||||
	//     user: black-mage-via-file
 | 
			
		||||
	//     user: black-mage-via-auth-provider
 | 
			
		||||
	//   alfa-as-white-mage:
 | 
			
		||||
	//     LocationOfOrigin: ""
 | 
			
		||||
	//     cluster: alfa
 | 
			
		||||
@@ -104,11 +107,15 @@ func Example_ofOptionsConfig() {
 | 
			
		||||
	//     LocationOfOrigin: ""
 | 
			
		||||
	//     cluster: bravo
 | 
			
		||||
	//     namespace: yankee
 | 
			
		||||
	//     user: black-mage-via-file
 | 
			
		||||
	//     user: black-mage-via-auth-provider
 | 
			
		||||
	// current-context: alfa-as-white-mage
 | 
			
		||||
	// preferences:
 | 
			
		||||
	//   colors: true
 | 
			
		||||
	// users:
 | 
			
		||||
	//   black-mage-via-auth-provider:
 | 
			
		||||
	//     LocationOfOrigin: ""
 | 
			
		||||
	//     auth-provider:
 | 
			
		||||
	//       name: gcp
 | 
			
		||||
	//   red-mage-via-token:
 | 
			
		||||
	//     LocationOfOrigin: ""
 | 
			
		||||
	//     token: my-secret-token
 | 
			
		||||
 
 | 
			
		||||
@@ -88,6 +88,8 @@ type AuthInfo struct {
 | 
			
		||||
	Username string `json:"username,omitempty"`
 | 
			
		||||
	// Password is the password for basic authentication to the kubernetes cluster.
 | 
			
		||||
	Password string `json:"password,omitempty"`
 | 
			
		||||
	// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
 | 
			
		||||
	AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"`
 | 
			
		||||
	// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
 | 
			
		||||
	Extensions []NamedExtension `json:"extensions,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
@@ -135,3 +137,8 @@ type NamedExtension struct {
 | 
			
		||||
	// Extension holds the extension information
 | 
			
		||||
	Extension runtime.RawExtension `json:"extension"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthProviderConfig holds the configuration for a specified auth provider.
 | 
			
		||||
type AuthProviderConfig struct {
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -172,6 +172,9 @@ func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fa
 | 
			
		||||
		mergedConfig.Username = configAuthInfo.Username
 | 
			
		||||
		mergedConfig.Password = configAuthInfo.Password
 | 
			
		||||
	}
 | 
			
		||||
	if configAuthInfo.AuthProvider != nil {
 | 
			
		||||
		mergedConfig.AuthProvider = configAuthInfo.AuthProvider
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if there still isn't enough information to authenticate the user, try prompting
 | 
			
		||||
	if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
 | 
			
		||||
@@ -212,8 +215,8 @@ func makeServerIdentificationConfig(info clientauth.Info) restclient.Config {
 | 
			
		||||
func canIdentifyUser(config restclient.Config) bool {
 | 
			
		||||
	return len(config.Username) > 0 ||
 | 
			
		||||
		(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
 | 
			
		||||
		len(config.BearerToken) > 0
 | 
			
		||||
 | 
			
		||||
		len(config.BearerToken) > 0 ||
 | 
			
		||||
		config.AuthProvider != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Namespace implements KubeConfig
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/client/typed/discovery"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/version"
 | 
			
		||||
	// Import solely to initialize client auth plugins.
 | 
			
		||||
	_ "k8s.io/kubernetes/plugin/pkg/client/auth"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								plugin/pkg/client/auth/gcp/gcp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								plugin/pkg/client/auth/gcp/gcp.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 gcp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/google"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/client/restclient"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	if err := restclient.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil {
 | 
			
		||||
		glog.Fatalf("Failed to register gcp auth plugin: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gcpAuthProvider struct {
 | 
			
		||||
	tokenSource oauth2.TokenSource
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGCPAuthProvider() (restclient.AuthProvider, error) {
 | 
			
		||||
	ts, err := google.DefaultTokenSource(context.TODO(), "https://www.googleapis.com/auth/cloud-platform")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &gcpAuthProvider{ts}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *gcpAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
			
		||||
	return &oauth2.Transport{
 | 
			
		||||
		Source: g.tokenSource,
 | 
			
		||||
		Base:   rt,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								plugin/pkg/client/auth/plugins.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								plugin/pkg/client/auth/plugins.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 plugins
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	// Initialize all known client auth plugins.
 | 
			
		||||
	_ "k8s.io/kubernetes/plugin/pkg/client/auth/gcp"
 | 
			
		||||
)
 | 
			
		||||
		Reference in New Issue
	
	Block a user