git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server

subrepo:
  subdir:   "metrics-server"
  merged:   "92d8412"
upstream:
  origin:   "https://github.com/kubernetes-incubator/metrics-server.git"
  branch:   "master"
  commit:   "92d8412"
git-subrepo:
  version:  "0.4.0"
  origin:   "???"
  commit:   "???"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go
new file mode 100644
index 0000000..fd3d038
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go
@@ -0,0 +1,68 @@
+/*
+Copyright 2014 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 authenticator
+
+import (
+	"net/http"
+
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// Token checks a string value against a backing authentication store and returns
+// information about the current user and true if successful, false if not successful,
+// or an error if the token could not be checked.
+type Token interface {
+	AuthenticateToken(token string) (user.Info, bool, error)
+}
+
+// Request attempts to extract authentication information from a request and returns
+// information about the current user and true if successful, false if not successful,
+// or an error if the request could not be checked.
+type Request interface {
+	AuthenticateRequest(req *http.Request) (user.Info, bool, error)
+}
+
+// Password checks a username and password against a backing authentication store and
+// returns information about the user and true if successful, false if not successful,
+// or an error if the username and password could not be checked
+type Password interface {
+	AuthenticatePassword(user, password string) (user.Info, bool, error)
+}
+
+// TokenFunc is a function that implements the Token interface.
+type TokenFunc func(token string) (user.Info, bool, error)
+
+// AuthenticateToken implements authenticator.Token.
+func (f TokenFunc) AuthenticateToken(token string) (user.Info, bool, error) {
+	return f(token)
+}
+
+// RequestFunc is a function that implements the Request interface.
+type RequestFunc func(req *http.Request) (user.Info, bool, error)
+
+// AuthenticateRequest implements authenticator.Request.
+func (f RequestFunc) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	return f(req)
+}
+
+// PasswordFunc is a function that implements the Password interface.
+type PasswordFunc func(user, password string) (user.Info, bool, error)
+
+// AuthenticatePassword implements authenticator.Password.
+func (f PasswordFunc) AuthenticatePassword(user, password string) (user.Info, bool, error) {
+	return f(user, password)
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go
new file mode 100644
index 0000000..61114c1
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go
@@ -0,0 +1,115 @@
+/*
+Copyright 2016 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 authenticatorfactory
+
+import (
+	"errors"
+	"fmt"
+	"time"
+
+	"github.com/go-openapi/spec"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/group"
+	"k8s.io/apiserver/pkg/authentication/request/anonymous"
+	"k8s.io/apiserver/pkg/authentication/request/bearertoken"
+	"k8s.io/apiserver/pkg/authentication/request/headerrequest"
+	unionauth "k8s.io/apiserver/pkg/authentication/request/union"
+	"k8s.io/apiserver/pkg/authentication/request/websocket"
+	"k8s.io/apiserver/pkg/authentication/request/x509"
+	webhooktoken "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
+	authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
+	"k8s.io/client-go/util/cert"
+)
+
+// DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator
+// built to delegate authentication to a kube API server
+type DelegatingAuthenticatorConfig struct {
+	Anonymous bool
+
+	TokenAccessReviewClient authenticationclient.TokenReviewInterface
+
+	// CacheTTL is the length of time that a token authentication answer will be cached.
+	CacheTTL time.Duration
+
+	// ClientCAFile is the CA bundle file used to authenticate client certificates
+	ClientCAFile string
+
+	RequestHeaderConfig *RequestHeaderConfig
+}
+
+func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.SecurityDefinitions, error) {
+	authenticators := []authenticator.Request{}
+	securityDefinitions := spec.SecurityDefinitions{}
+
+	// front-proxy first, then remote
+	// Add the front proxy authenticator if requested
+	if c.RequestHeaderConfig != nil {
+		requestHeaderAuthenticator, err := headerrequest.NewSecure(
+			c.RequestHeaderConfig.ClientCA,
+			c.RequestHeaderConfig.AllowedClientNames,
+			c.RequestHeaderConfig.UsernameHeaders,
+			c.RequestHeaderConfig.GroupHeaders,
+			c.RequestHeaderConfig.ExtraHeaderPrefixes,
+		)
+		if err != nil {
+			return nil, nil, err
+		}
+		authenticators = append(authenticators, requestHeaderAuthenticator)
+	}
+
+	// x509 client cert auth
+	if len(c.ClientCAFile) > 0 {
+		clientCAs, err := cert.NewPool(c.ClientCAFile)
+		if err != nil {
+			return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err)
+		}
+		verifyOpts := x509.DefaultVerifyOptions()
+		verifyOpts.Roots = clientCAs
+		authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion))
+	}
+
+	if c.TokenAccessReviewClient != nil {
+		tokenAuth, err := webhooktoken.NewFromInterface(c.TokenAccessReviewClient, c.CacheTTL)
+		if err != nil {
+			return nil, nil, err
+		}
+		authenticators = append(authenticators, bearertoken.New(tokenAuth), websocket.NewProtocolAuthenticator(tokenAuth))
+
+		securityDefinitions["BearerToken"] = &spec.SecurityScheme{
+			SecuritySchemeProps: spec.SecuritySchemeProps{
+				Type:        "apiKey",
+				Name:        "authorization",
+				In:          "header",
+				Description: "Bearer Token authentication",
+			},
+		}
+	}
+
+	if len(authenticators) == 0 {
+		if c.Anonymous {
+			return anonymous.NewAuthenticator(), &securityDefinitions, nil
+		}
+		return nil, nil, errors.New("No authentication method configured")
+	}
+
+	authenticator := group.NewAuthenticatedGroupAdder(unionauth.New(authenticators...))
+	if c.Anonymous {
+		authenticator = unionauth.NewFailOnError(authenticator, anonymous.NewAuthenticator())
+	}
+	return authenticator, &securityDefinitions, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/loopback.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/loopback.go
new file mode 100644
index 0000000..f316565
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/loopback.go
@@ -0,0 +1,29 @@
+/*
+Copyright 2016 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 authenticatorfactory
+
+import (
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/request/bearertoken"
+	"k8s.io/apiserver/pkg/authentication/token/tokenfile"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// NewFromTokens returns an authenticator.Request or an error
+func NewFromTokens(tokens map[string]*user.DefaultInfo) authenticator.Request {
+	return bearertoken.New(tokenfile.New(tokens))
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go
new file mode 100644
index 0000000..3eeb238
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go
@@ -0,0 +1,31 @@
+/*
+Copyright 2014 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 authenticatorfactory
+
+type RequestHeaderConfig struct {
+	// UsernameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins.
+	UsernameHeaders []string
+	// GroupHeaders are the headers to check (case-insensitively) for a group names.  All values will be used.
+	GroupHeaders []string
+	// ExtraHeaderPrefixes are the head prefixes to check (case-insentively) for filling in
+	// the user.Info.Extra.  All values of all matching headers will be added.
+	ExtraHeaderPrefixes []string
+	// ClientCA points to CA bundle file which is used verify the identity of the front proxy
+	ClientCA string
+	// AllowedClientNames is a list of common names that may be presented by the authenticating front proxy.  Empty means: accept any.
+	AllowedClientNames []string
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
new file mode 100644
index 0000000..9f0453b
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/authenticated_group_adder.go
@@ -0,0 +1,60 @@
+/*
+Copyright 2017 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 group
+
+import (
+	"net/http"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// AuthenticatedGroupAdder adds system:authenticated group when appropriate
+type AuthenticatedGroupAdder struct {
+	// Authenticator is delegated to make the authentication decision
+	Authenticator authenticator.Request
+}
+
+// NewAuthenticatedGroupAdder wraps a request authenticator, and adds the system:authenticated group when appropriate.
+// Authentication must succeed, the user must not be system:anonymous, the groups system:authenticated or system:unauthenticated must
+// not be present
+func NewAuthenticatedGroupAdder(auth authenticator.Request) authenticator.Request {
+	return &AuthenticatedGroupAdder{auth}
+}
+
+func (g *AuthenticatedGroupAdder) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	u, ok, err := g.Authenticator.AuthenticateRequest(req)
+	if err != nil || !ok {
+		return nil, ok, err
+	}
+
+	if u.GetName() == user.Anonymous {
+		return u, true, nil
+	}
+	for _, group := range u.GetGroups() {
+		if group == user.AllAuthenticated || group == user.AllUnauthenticated {
+			return u, true, nil
+		}
+	}
+
+	return &user.DefaultInfo{
+		Name:   u.GetName(),
+		UID:    u.GetUID(),
+		Groups: append(u.GetGroups(), user.AllAuthenticated),
+		Extra:  u.GetExtra(),
+	}, true, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/group_adder.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/group_adder.go
new file mode 100644
index 0000000..1f71429
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/group_adder.go
@@ -0,0 +1,50 @@
+/*
+Copyright 2016 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 group
+
+import (
+	"net/http"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// GroupAdder adds groups to an authenticated user.Info
+type GroupAdder struct {
+	// Authenticator is delegated to make the authentication decision
+	Authenticator authenticator.Request
+	// Groups are additional groups to add to the user.Info from a successful authentication
+	Groups []string
+}
+
+// NewGroupAdder wraps a request authenticator, and adds the specified groups to the returned user when authentication succeeds
+func NewGroupAdder(auth authenticator.Request, groups []string) authenticator.Request {
+	return &GroupAdder{auth, groups}
+}
+
+func (g *GroupAdder) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	u, ok, err := g.Authenticator.AuthenticateRequest(req)
+	if err != nil || !ok {
+		return nil, ok, err
+	}
+	return &user.DefaultInfo{
+		Name:   u.GetName(),
+		UID:    u.GetUID(),
+		Groups: append(u.GetGroups(), g.Groups...),
+		Extra:  u.GetExtra(),
+	}, true, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/token_group_adder.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/token_group_adder.go
new file mode 100644
index 0000000..4f60d52
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/group/token_group_adder.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2017 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 group
+
+import (
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// TokenGroupAdder adds groups to an authenticated user.Info
+type TokenGroupAdder struct {
+	// Authenticator is delegated to make the authentication decision
+	Authenticator authenticator.Token
+	// Groups are additional groups to add to the user.Info from a successful authentication
+	Groups []string
+}
+
+// NewTokenGroupAdder wraps a token authenticator, and adds the specified groups to the returned user when authentication succeeds
+func NewTokenGroupAdder(auth authenticator.Token, groups []string) authenticator.Token {
+	return &TokenGroupAdder{auth, groups}
+}
+
+func (g *TokenGroupAdder) AuthenticateToken(token string) (user.Info, bool, error) {
+	u, ok, err := g.Authenticator.AuthenticateToken(token)
+	if err != nil || !ok {
+		return nil, ok, err
+	}
+	return &user.DefaultInfo{
+		Name:   u.GetName(),
+		UID:    u.GetUID(),
+		Groups: append(u.GetGroups(), g.Groups...),
+		Extra:  u.GetExtra(),
+	}, true, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/anonymous/anonymous.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/anonymous/anonymous.go
new file mode 100644
index 0000000..a6d2294
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/anonymous/anonymous.go
@@ -0,0 +1,36 @@
+/*
+Copyright 2016 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 anonymous
+
+import (
+	"net/http"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+const (
+	anonymousUser = user.Anonymous
+
+	unauthenticatedGroup = user.AllUnauthenticated
+)
+
+func NewAuthenticator() authenticator.Request {
+	return authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
+		return &user.DefaultInfo{Name: anonymousUser, Groups: []string{unauthenticatedGroup}}, true, nil
+	})
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken/bearertoken.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken/bearertoken.go
new file mode 100644
index 0000000..5ca22f3
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/bearertoken/bearertoken.go
@@ -0,0 +1,68 @@
+/*
+Copyright 2014 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 bearertoken
+
+import (
+	"errors"
+	"net/http"
+	"strings"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+type Authenticator struct {
+	auth authenticator.Token
+}
+
+func New(auth authenticator.Token) *Authenticator {
+	return &Authenticator{auth}
+}
+
+var invalidToken = errors.New("invalid bearer token")
+
+func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	auth := strings.TrimSpace(req.Header.Get("Authorization"))
+	if auth == "" {
+		return nil, false, nil
+	}
+	parts := strings.Split(auth, " ")
+	if len(parts) < 2 || strings.ToLower(parts[0]) != "bearer" {
+		return nil, false, nil
+	}
+
+	token := parts[1]
+
+	// Empty bearer tokens aren't valid
+	if len(token) == 0 {
+		return nil, false, nil
+	}
+
+	user, ok, err := a.auth.AuthenticateToken(token)
+	// if we authenticated successfully, go ahead and remove the bearer token so that no one
+	// is ever tempted to use it inside of the API server
+	if ok {
+		req.Header.Del("Authorization")
+	}
+
+	// If the token authenticator didn't error, provide a default error
+	if !ok && err == nil {
+		err = invalidToken
+	}
+
+	return user, ok, err
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go
new file mode 100644
index 0000000..948478b
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go
@@ -0,0 +1,188 @@
+/*
+Copyright 2016 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 headerrequest
+
+import (
+	"crypto/x509"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"strings"
+
+	"k8s.io/apimachinery/pkg/util/sets"
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	x509request "k8s.io/apiserver/pkg/authentication/request/x509"
+	"k8s.io/apiserver/pkg/authentication/user"
+	utilcert "k8s.io/client-go/util/cert"
+)
+
+type requestHeaderAuthRequestHandler struct {
+	// nameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins.
+	nameHeaders []string
+
+	// groupHeaders are the headers to check (case-insensitively) for group membership.  All values of all headers will be added.
+	groupHeaders []string
+
+	// extraHeaderPrefixes are the head prefixes to check (case-insensitively) for filling in
+	// the user.Info.Extra.  All values of all matching headers will be added.
+	extraHeaderPrefixes []string
+}
+
+func New(nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) {
+	trimmedNameHeaders, err := trimHeaders(nameHeaders...)
+	if err != nil {
+		return nil, err
+	}
+	trimmedGroupHeaders, err := trimHeaders(groupHeaders...)
+	if err != nil {
+		return nil, err
+	}
+	trimmedExtraHeaderPrefixes, err := trimHeaders(extraHeaderPrefixes...)
+	if err != nil {
+		return nil, err
+	}
+
+	return &requestHeaderAuthRequestHandler{
+		nameHeaders:         trimmedNameHeaders,
+		groupHeaders:        trimmedGroupHeaders,
+		extraHeaderPrefixes: trimmedExtraHeaderPrefixes,
+	}, nil
+}
+
+func trimHeaders(headerNames ...string) ([]string, error) {
+	ret := []string{}
+	for _, headerName := range headerNames {
+		trimmedHeader := strings.TrimSpace(headerName)
+		if len(trimmedHeader) == 0 {
+			return nil, fmt.Errorf("empty header %q", headerName)
+		}
+		ret = append(ret, trimmedHeader)
+	}
+
+	return ret, nil
+}
+
+func NewSecure(clientCA string, proxyClientNames []string, nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) {
+	headerAuthenticator, err := New(nameHeaders, groupHeaders, extraHeaderPrefixes)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(clientCA) == 0 {
+		return nil, fmt.Errorf("missing clientCA file")
+	}
+
+	// Wrap with an x509 verifier
+	caData, err := ioutil.ReadFile(clientCA)
+	if err != nil {
+		return nil, fmt.Errorf("error reading %s: %v", clientCA, err)
+	}
+	opts := x509request.DefaultVerifyOptions()
+	opts.Roots = x509.NewCertPool()
+	certs, err := utilcert.ParseCertsPEM(caData)
+	if err != nil {
+		return nil, fmt.Errorf("error loading certs from  %s: %v", clientCA, err)
+	}
+	for _, cert := range certs {
+		opts.Roots.AddCert(cert)
+	}
+
+	return x509request.NewVerifier(opts, headerAuthenticator, sets.NewString(proxyClientNames...)), nil
+}
+
+func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	name := headerValue(req.Header, a.nameHeaders)
+	if len(name) == 0 {
+		return nil, false, nil
+	}
+	groups := allHeaderValues(req.Header, a.groupHeaders)
+	extra := newExtra(req.Header, a.extraHeaderPrefixes)
+
+	// clear headers used for authentication
+	for _, headerName := range a.nameHeaders {
+		req.Header.Del(headerName)
+	}
+	for _, headerName := range a.groupHeaders {
+		req.Header.Del(headerName)
+	}
+	for k := range extra {
+		for _, prefix := range a.extraHeaderPrefixes {
+			req.Header.Del(prefix + k)
+		}
+	}
+
+	return &user.DefaultInfo{
+		Name:   name,
+		Groups: groups,
+		Extra:  extra,
+	}, true, nil
+}
+
+func headerValue(h http.Header, headerNames []string) string {
+	for _, headerName := range headerNames {
+		headerValue := h.Get(headerName)
+		if len(headerValue) > 0 {
+			return headerValue
+		}
+	}
+	return ""
+}
+
+func allHeaderValues(h http.Header, headerNames []string) []string {
+	ret := []string{}
+	for _, headerName := range headerNames {
+		headerKey := http.CanonicalHeaderKey(headerName)
+		values, ok := h[headerKey]
+		if !ok {
+			continue
+		}
+
+		for _, headerValue := range values {
+			if len(headerValue) > 0 {
+				ret = append(ret, headerValue)
+			}
+		}
+	}
+	return ret
+}
+
+func unescapeExtraKey(encodedKey string) string {
+	key, err := url.PathUnescape(encodedKey) // Decode %-encoded bytes.
+	if err != nil {
+		return encodedKey // Always record extra strings, even if malformed/unencoded.
+	}
+	return key
+}
+
+func newExtra(h http.Header, headerPrefixes []string) map[string][]string {
+	ret := map[string][]string{}
+
+	// we have to iterate over prefixes first in order to have proper ordering inside the value slices
+	for _, prefix := range headerPrefixes {
+		for headerName, vv := range h {
+			if !strings.HasPrefix(strings.ToLower(headerName), strings.ToLower(prefix)) {
+				continue
+			}
+
+			extraKey := unescapeExtraKey(strings.ToLower(headerName[len(prefix):]))
+			ret[extraKey] = append(ret[extraKey], vv...)
+		}
+	}
+
+	return ret
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
new file mode 100644
index 0000000..1613940
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/union/union.go
@@ -0,0 +1,72 @@
+/*
+Copyright 2014 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 union
+
+import (
+	"net/http"
+
+	utilerrors "k8s.io/apimachinery/pkg/util/errors"
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+// unionAuthRequestHandler authenticates requests using a chain of authenticator.Requests
+type unionAuthRequestHandler struct {
+	// Handlers is a chain of request authenticators to delegate to
+	Handlers []authenticator.Request
+	// FailOnError determines whether an error returns short-circuits the chain
+	FailOnError bool
+}
+
+// New returns a request authenticator that validates credentials using a chain of authenticator.Request objects.
+// The entire chain is tried until one succeeds. If all fail, an aggregate error is returned.
+func New(authRequestHandlers ...authenticator.Request) authenticator.Request {
+	if len(authRequestHandlers) == 1 {
+		return authRequestHandlers[0]
+	}
+	return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: false}
+}
+
+// NewFailOnError returns a request authenticator that validates credentials using a chain of authenticator.Request objects.
+// The first error short-circuits the chain.
+func NewFailOnError(authRequestHandlers ...authenticator.Request) authenticator.Request {
+	if len(authRequestHandlers) == 1 {
+		return authRequestHandlers[0]
+	}
+	return &unionAuthRequestHandler{Handlers: authRequestHandlers, FailOnError: true}
+}
+
+// AuthenticateRequest authenticates the request using a chain of authenticator.Request objects.
+func (authHandler *unionAuthRequestHandler) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	var errlist []error
+	for _, currAuthRequestHandler := range authHandler.Handlers {
+		info, ok, err := currAuthRequestHandler.AuthenticateRequest(req)
+		if err != nil {
+			if authHandler.FailOnError {
+				return info, ok, err
+			}
+			errlist = append(errlist, err)
+			continue
+		}
+
+		if ok {
+			return info, ok, err
+		}
+	}
+
+	return nil, false, utilerrors.NewAggregate(errlist)
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/websocket/protocol.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/websocket/protocol.go
new file mode 100644
index 0000000..4a30bb6
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/websocket/protocol.go
@@ -0,0 +1,109 @@
+/*
+Copyright 2017 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 websocket
+
+import (
+	"encoding/base64"
+	"errors"
+	"net/http"
+	"net/textproto"
+	"strings"
+	"unicode/utf8"
+
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+	"k8s.io/apiserver/pkg/util/wsstream"
+)
+
+const bearerProtocolPrefix = "base64url.bearer.authorization.k8s.io."
+
+var protocolHeader = textproto.CanonicalMIMEHeaderKey("Sec-WebSocket-Protocol")
+
+var errInvalidToken = errors.New("invalid bearer token")
+
+// ProtocolAuthenticator allows a websocket connection to provide a bearer token as a subprotocol
+// in the format "base64url.bearer.authorization.<base64url-without-padding(bearer-token)>"
+type ProtocolAuthenticator struct {
+	// auth is the token authenticator to use to validate the token
+	auth authenticator.Token
+}
+
+func NewProtocolAuthenticator(auth authenticator.Token) *ProtocolAuthenticator {
+	return &ProtocolAuthenticator{auth}
+}
+
+func (a *ProtocolAuthenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	// Only accept websocket connections
+	if !wsstream.IsWebSocketRequest(req) {
+		return nil, false, nil
+	}
+
+	token := ""
+	sawTokenProtocol := false
+	filteredProtocols := []string{}
+	for _, protocolHeader := range req.Header[protocolHeader] {
+		for _, protocol := range strings.Split(protocolHeader, ",") {
+			protocol = strings.TrimSpace(protocol)
+
+			if !strings.HasPrefix(protocol, bearerProtocolPrefix) {
+				filteredProtocols = append(filteredProtocols, protocol)
+				continue
+			}
+
+			if sawTokenProtocol {
+				return nil, false, errors.New("multiple base64.bearer.authorization tokens specified")
+			}
+			sawTokenProtocol = true
+
+			encodedToken := strings.TrimPrefix(protocol, bearerProtocolPrefix)
+			decodedToken, err := base64.RawURLEncoding.DecodeString(encodedToken)
+			if err != nil {
+				return nil, false, errors.New("invalid base64.bearer.authorization token encoding")
+			}
+			if !utf8.Valid(decodedToken) {
+				return nil, false, errors.New("invalid base64.bearer.authorization token")
+			}
+			token = string(decodedToken)
+		}
+	}
+
+	// Must pass at least one other subprotocol so that we can remove the one containing the bearer token,
+	// and there is at least one to echo back to the client
+	if len(token) > 0 && len(filteredProtocols) == 0 {
+		return nil, false, errors.New("missing additional subprotocol")
+	}
+
+	if len(token) == 0 {
+		return nil, false, nil
+	}
+
+	user, ok, err := a.auth.AuthenticateToken(token)
+
+	// on success, remove the protocol with the token
+	if ok {
+		// https://tools.ietf.org/html/rfc6455#section-11.3.4 indicates the Sec-WebSocket-Protocol header may appear multiple times
+		// in a request, and is logically the same as a single Sec-WebSocket-Protocol header field that contains all values
+		req.Header.Set(protocolHeader, strings.Join(filteredProtocols, ","))
+	}
+
+	// If the token authenticator didn't error, provide a default error
+	if !ok && err == nil {
+		err = errInvalidToken
+	}
+
+	return user, ok, err
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/doc.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/doc.go
new file mode 100644
index 0000000..8f3d36b
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2014 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 x509 provides a request authenticator that validates and
+// extracts user information from client certificates
+package x509 // import "k8s.io/apiserver/pkg/authentication/request/x509"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go
new file mode 100644
index 0000000..708a89e
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go
@@ -0,0 +1,215 @@
+/*
+Copyright 2014 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 x509
+
+import (
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"fmt"
+	"net/http"
+	"time"
+
+	"github.com/golang/glog"
+	"github.com/prometheus/client_golang/prometheus"
+
+	utilerrors "k8s.io/apimachinery/pkg/util/errors"
+	"k8s.io/apimachinery/pkg/util/sets"
+	"k8s.io/apiserver/pkg/authentication/authenticator"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+var clientCertificateExpirationHistogram = prometheus.NewHistogram(
+	prometheus.HistogramOpts{
+		Namespace: "apiserver",
+		Subsystem: "client",
+		Name:      "certificate_expiration_seconds",
+		Help:      "Distribution of the remaining lifetime on the certificate used to authenticate a request.",
+		Buckets: []float64{
+			0,
+			(6 * time.Hour).Seconds(),
+			(12 * time.Hour).Seconds(),
+			(24 * time.Hour).Seconds(),
+			(2 * 24 * time.Hour).Seconds(),
+			(4 * 24 * time.Hour).Seconds(),
+			(7 * 24 * time.Hour).Seconds(),
+			(30 * 24 * time.Hour).Seconds(),
+			(3 * 30 * 24 * time.Hour).Seconds(),
+			(6 * 30 * 24 * time.Hour).Seconds(),
+			(12 * 30 * 24 * time.Hour).Seconds(),
+		},
+	},
+)
+
+func init() {
+	prometheus.MustRegister(clientCertificateExpirationHistogram)
+}
+
+// UserConversion defines an interface for extracting user info from a client certificate chain
+type UserConversion interface {
+	User(chain []*x509.Certificate) (user.Info, bool, error)
+}
+
+// UserConversionFunc is a function that implements the UserConversion interface.
+type UserConversionFunc func(chain []*x509.Certificate) (user.Info, bool, error)
+
+// User implements x509.UserConversion
+func (f UserConversionFunc) User(chain []*x509.Certificate) (user.Info, bool, error) {
+	return f(chain)
+}
+
+// Authenticator implements request.Authenticator by extracting user info from verified client certificates
+type Authenticator struct {
+	opts x509.VerifyOptions
+	user UserConversion
+}
+
+// New returns a request.Authenticator that verifies client certificates using the provided
+// VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion
+func New(opts x509.VerifyOptions, user UserConversion) *Authenticator {
+	return &Authenticator{opts, user}
+}
+
+// AuthenticateRequest authenticates the request using presented client certificates
+func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
+		return nil, false, nil
+	}
+
+	// Use intermediates, if provided
+	optsCopy := a.opts
+	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
+		optsCopy.Intermediates = x509.NewCertPool()
+		for _, intermediate := range req.TLS.PeerCertificates[1:] {
+			optsCopy.Intermediates.AddCert(intermediate)
+		}
+	}
+
+	remaining := req.TLS.PeerCertificates[0].NotAfter.Sub(time.Now())
+	clientCertificateExpirationHistogram.Observe(remaining.Seconds())
+	chains, err := req.TLS.PeerCertificates[0].Verify(optsCopy)
+	if err != nil {
+		return nil, false, err
+	}
+
+	var errlist []error
+	for _, chain := range chains {
+		user, ok, err := a.user.User(chain)
+		if err != nil {
+			errlist = append(errlist, err)
+			continue
+		}
+
+		if ok {
+			return user, ok, err
+		}
+	}
+	return nil, false, utilerrors.NewAggregate(errlist)
+}
+
+// Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
+type Verifier struct {
+	opts x509.VerifyOptions
+	auth authenticator.Request
+
+	// allowedCommonNames contains the common names which a verified certificate is allowed to have.
+	// If empty, all verified certificates are allowed.
+	allowedCommonNames sets.String
+}
+
+// NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth
+func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request {
+	return &Verifier{opts, auth, allowedCommonNames}
+}
+
+// AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth
+func (a *Verifier) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
+	if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
+		return nil, false, nil
+	}
+
+	// Use intermediates, if provided
+	optsCopy := a.opts
+	if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 {
+		optsCopy.Intermediates = x509.NewCertPool()
+		for _, intermediate := range req.TLS.PeerCertificates[1:] {
+			optsCopy.Intermediates.AddCert(intermediate)
+		}
+	}
+
+	if _, err := req.TLS.PeerCertificates[0].Verify(optsCopy); err != nil {
+		return nil, false, err
+	}
+	if err := a.verifySubject(req.TLS.PeerCertificates[0].Subject); err != nil {
+		return nil, false, err
+	}
+	return a.auth.AuthenticateRequest(req)
+}
+
+func (a *Verifier) verifySubject(subject pkix.Name) error {
+	// No CN restrictions
+	if len(a.allowedCommonNames) == 0 {
+		return nil
+	}
+	// Enforce CN restrictions
+	if a.allowedCommonNames.Has(subject.CommonName) {
+		return nil
+	}
+	glog.Warningf("x509: subject with cn=%s is not in the allowed list: %v", subject.CommonName, a.allowedCommonNames.List())
+	return fmt.Errorf("x509: subject with cn=%s is not allowed", subject.CommonName)
+}
+
+// DefaultVerifyOptions returns VerifyOptions that use the system root certificates, current time,
+// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth)
+func DefaultVerifyOptions() x509.VerifyOptions {
+	return x509.VerifyOptions{
+		KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+	}
+}
+
+// CommonNameUserConversion builds user info from a certificate chain using the subject's CommonName
+var CommonNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
+	if len(chain[0].Subject.CommonName) == 0 {
+		return nil, false, nil
+	}
+	return &user.DefaultInfo{
+		Name:   chain[0].Subject.CommonName,
+		Groups: chain[0].Subject.Organization,
+	}, true, nil
+})
+
+// DNSNameUserConversion builds user info from a certificate chain using the first DNSName on the certificate
+var DNSNameUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
+	if len(chain[0].DNSNames) == 0 {
+		return nil, false, nil
+	}
+	return &user.DefaultInfo{Name: chain[0].DNSNames[0]}, true, nil
+})
+
+// EmailAddressUserConversion builds user info from a certificate chain using the first EmailAddress on the certificate
+var EmailAddressUserConversion = UserConversionFunc(func(chain []*x509.Certificate) (user.Info, bool, error) {
+	var emailAddressOID asn1.ObjectIdentifier = []int{1, 2, 840, 113549, 1, 9, 1}
+	if len(chain[0].EmailAddresses) == 0 {
+		for _, name := range chain[0].Subject.Names {
+			if name.Type.Equal(emailAddressOID) {
+				return &user.DefaultInfo{Name: name.Value.(string)}, true, nil
+			}
+		}
+		return nil, false, nil
+	}
+	return &user.DefaultInfo{Name: chain[0].EmailAddresses[0]}, true, nil
+})
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go
new file mode 100644
index 0000000..1b7bbc1
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go
@@ -0,0 +1,73 @@
+/*
+Copyright 2014 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 serviceaccount
+
+import (
+	"fmt"
+	"strings"
+
+	apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
+)
+
+const (
+	ServiceAccountUsernamePrefix    = "system:serviceaccount:"
+	ServiceAccountUsernameSeparator = ":"
+	ServiceAccountGroupPrefix       = "system:serviceaccounts:"
+	AllServiceAccountsGroup         = "system:serviceaccounts"
+)
+
+// MakeUsername generates a username from the given namespace and ServiceAccount name.
+// The resulting username can be passed to SplitUsername to extract the original namespace and ServiceAccount name.
+func MakeUsername(namespace, name string) string {
+	return ServiceAccountUsernamePrefix + namespace + ServiceAccountUsernameSeparator + name
+}
+
+var invalidUsernameErr = fmt.Errorf("Username must be in the form %s", MakeUsername("namespace", "name"))
+
+// SplitUsername returns the namespace and ServiceAccount name embedded in the given username,
+// or an error if the username is not a valid name produced by MakeUsername
+func SplitUsername(username string) (string, string, error) {
+	if !strings.HasPrefix(username, ServiceAccountUsernamePrefix) {
+		return "", "", invalidUsernameErr
+	}
+	trimmed := strings.TrimPrefix(username, ServiceAccountUsernamePrefix)
+	parts := strings.Split(trimmed, ServiceAccountUsernameSeparator)
+	if len(parts) != 2 {
+		return "", "", invalidUsernameErr
+	}
+	namespace, name := parts[0], parts[1]
+	if len(apimachineryvalidation.ValidateNamespaceName(namespace, false)) != 0 {
+		return "", "", invalidUsernameErr
+	}
+	if len(apimachineryvalidation.ValidateServiceAccountName(name, false)) != 0 {
+		return "", "", invalidUsernameErr
+	}
+	return namespace, name, nil
+}
+
+// MakeGroupNames generates service account group names for the given namespace
+func MakeGroupNames(namespace string) []string {
+	return []string{
+		AllServiceAccountsGroup,
+		MakeNamespaceGroupName(namespace),
+	}
+}
+
+// MakeNamespaceGroupName returns the name of the group all service accounts in the namespace are included in
+func MakeNamespaceGroupName(namespace string) string {
+	return ServiceAccountGroupPrefix + namespace
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile/tokenfile.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile/tokenfile.go
new file mode 100644
index 0000000..57bb6c5
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/token/tokenfile/tokenfile.go
@@ -0,0 +1,97 @@
+/*
+Copyright 2014 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 tokenfile
+
+import (
+	"encoding/csv"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/golang/glog"
+	"k8s.io/apiserver/pkg/authentication/user"
+)
+
+type TokenAuthenticator struct {
+	tokens map[string]*user.DefaultInfo
+}
+
+// New returns a TokenAuthenticator for a single token
+func New(tokens map[string]*user.DefaultInfo) *TokenAuthenticator {
+	return &TokenAuthenticator{
+		tokens: tokens,
+	}
+}
+
+// NewCSV returns a TokenAuthenticator, populated from a CSV file.
+// The CSV file must contain records in the format "token,username,useruid"
+func NewCSV(path string) (*TokenAuthenticator, error) {
+	file, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	recordNum := 0
+	tokens := make(map[string]*user.DefaultInfo)
+	reader := csv.NewReader(file)
+	reader.FieldsPerRecord = -1
+	for {
+		record, err := reader.Read()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+		if len(record) < 3 {
+			return nil, fmt.Errorf("token file '%s' must have at least 3 columns (token, user name, user uid), found %d", path, len(record))
+		}
+
+		recordNum++
+		if record[0] == "" {
+			glog.Warningf("empty token has been found in token file '%s', record number '%d'", path, recordNum)
+			continue
+		}
+
+		obj := &user.DefaultInfo{
+			Name: record[1],
+			UID:  record[2],
+		}
+		if _, exist := tokens[record[0]]; exist {
+			glog.Warningf("duplicate token has been found in token file '%s', record number '%d'", path, recordNum)
+		}
+		tokens[record[0]] = obj
+
+		if len(record) >= 4 {
+			obj.Groups = strings.Split(record[3], ",")
+		}
+	}
+
+	return &TokenAuthenticator{
+		tokens: tokens,
+	}, nil
+}
+
+func (a *TokenAuthenticator) AuthenticateToken(value string) (user.Info, bool, error) {
+	user, ok := a.tokens[value]
+	if !ok {
+		return nil, false, nil
+	}
+	return user, true, nil
+}
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go
new file mode 100644
index 0000000..570c51a
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2014 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 user contains utilities for dealing with simple user exchange in the auth
+// packages. The user.Info interface defines an interface for exchanging that info.
+package user
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/user.go b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/user.go
new file mode 100644
index 0000000..f02dc39
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/authentication/user/user.go
@@ -0,0 +1,83 @@
+/*
+Copyright 2014 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 user
+
+// Info describes a user that has been authenticated to the system.
+type Info interface {
+	// GetName returns the name that uniquely identifies this user among all
+	// other active users.
+	GetName() string
+	// GetUID returns a unique value for a particular user that will change
+	// if the user is removed from the system and another user is added with
+	// the same name.
+	GetUID() string
+	// GetGroups returns the names of the groups the user is a member of
+	GetGroups() []string
+
+	// GetExtra can contain any additional information that the authenticator
+	// thought was interesting.  One example would be scopes on a token.
+	// Keys in this map should be namespaced to the authenticator or
+	// authenticator/authorizer pair making use of them.
+	// For instance: "example.org/foo" instead of "foo"
+	// This is a map[string][]string because it needs to be serializeable into
+	// a SubjectAccessReviewSpec.authorization.k8s.io for proper authorization
+	// delegation flows
+	// In order to faithfully round-trip through an impersonation flow, these keys
+	// MUST be lowercase.
+	GetExtra() map[string][]string
+}
+
+// DefaultInfo provides a simple user information exchange object
+// for components that implement the UserInfo interface.
+type DefaultInfo struct {
+	Name   string
+	UID    string
+	Groups []string
+	Extra  map[string][]string
+}
+
+func (i *DefaultInfo) GetName() string {
+	return i.Name
+}
+
+func (i *DefaultInfo) GetUID() string {
+	return i.UID
+}
+
+func (i *DefaultInfo) GetGroups() []string {
+	return i.Groups
+}
+
+func (i *DefaultInfo) GetExtra() map[string][]string {
+	return i.Extra
+}
+
+// well-known user and group names
+const (
+	SystemPrivilegedGroup = "system:masters"
+	NodesGroup            = "system:nodes"
+	AllUnauthenticated    = "system:unauthenticated"
+	AllAuthenticated      = "system:authenticated"
+
+	Anonymous     = "system:anonymous"
+	APIServerUser = "system:apiserver"
+
+	// core kubernetes process identities
+	KubeProxy             = "system:kube-proxy"
+	KubeControllerManager = "system:kube-controller-manager"
+	KubeScheduler         = "system:kube-scheduler"
+)