Vednor update for kube v1.13.2

Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
Humble Chirammal
2019-01-25 16:00:04 +05:30
parent cd8381690d
commit ac4c83c96c
6 changed files with 69 additions and 83 deletions

View File

@ -39,6 +39,11 @@ type Config struct {
// Bearer token for authentication
BearerToken string
// Path to a file containing a BearerToken.
// If set, the contents are periodically read.
// The last successfully read value takes precedence over BearerToken.
BearerTokenFile string
// Impersonate is the config that this Config will impersonate using
Impersonate ImpersonationConfig
@ -80,7 +85,7 @@ func (c *Config) HasBasicAuth() bool {
// HasTokenAuth returns whether the configuration has token authentication or not.
func (c *Config) HasTokenAuth() bool {
return len(c.BearerToken) != 0
return len(c.BearerToken) != 0 || len(c.BearerTokenFile) != 0
}
// HasCertAuth returns whether the configuration has certificate authentication or not.

View File

@ -22,6 +22,7 @@ import (
"strings"
"time"
"golang.org/x/oauth2"
"k8s.io/klog"
utilnet "k8s.io/apimachinery/pkg/util/net"
@ -44,7 +45,11 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip
case config.HasBasicAuth() && config.HasTokenAuth():
return nil, fmt.Errorf("username/password or bearer token may be set, but not both")
case config.HasTokenAuth():
rt = NewBearerAuthRoundTripper(config.BearerToken, rt)
var err error
rt, err = NewBearerAuthWithRefreshRoundTripper(config.BearerToken, config.BearerTokenFile, rt)
if err != nil {
return nil, err
}
case config.HasBasicAuth():
rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt)
}
@ -265,13 +270,35 @@ func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { r
type bearerAuthRoundTripper struct {
bearer string
source oauth2.TokenSource
rt http.RoundTripper
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request
// unless the authorization header has already been set.
func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthRoundTripper{bearer, rt}
return &bearerAuthRoundTripper{bearer, nil, rt}
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request
// unless the authorization header has already been set.
// If tokenFile is non-empty, it is periodically read,
// and the last successfully read content is used as the bearer token.
// If tokenFile is non-empty and bearer is empty, the tokenFile is read
// immediately to populate the initial bearer token.
func NewBearerAuthWithRefreshRoundTripper(bearer string, tokenFile string, rt http.RoundTripper) (http.RoundTripper, error) {
if len(tokenFile) == 0 {
return &bearerAuthRoundTripper{bearer, nil, rt}, nil
}
source := NewCachedFileTokenSource(tokenFile)
if len(bearer) == 0 {
token, err := source.Token()
if err != nil {
return nil, err
}
bearer = token.AccessToken
}
return &bearerAuthRoundTripper{bearer, source, rt}, nil
}
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
@ -280,7 +307,13 @@ func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response,
}
req = utilnet.CloneRequest(req)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rt.bearer))
token := rt.bearer
if rt.source != nil {
if refreshedToken, err := rt.source.Token(); err == nil {
token = refreshedToken.AccessToken
}
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
return rt.rt.RoundTrip(req)
}

140
vendor/k8s.io/client-go/transport/token_source.go generated vendored Normal file
View File

@ -0,0 +1,140 @@
/*
Copyright 2018 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 transport
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"time"
"golang.org/x/oauth2"
"k8s.io/klog"
)
// TokenSourceWrapTransport returns a WrapTransport that injects bearer tokens
// authentication from an oauth2.TokenSource.
func TokenSourceWrapTransport(ts oauth2.TokenSource) func(http.RoundTripper) http.RoundTripper {
return func(rt http.RoundTripper) http.RoundTripper {
return &tokenSourceTransport{
base: rt,
ort: &oauth2.Transport{
Source: ts,
Base: rt,
},
}
}
}
// NewCachedFileTokenSource returns a oauth2.TokenSource reads a token from a
// file at a specified path and periodically reloads it.
func NewCachedFileTokenSource(path string) oauth2.TokenSource {
return &cachingTokenSource{
now: time.Now,
leeway: 10 * time.Second,
base: &fileTokenSource{
path: path,
// This period was picked because it is half of the duration between when the kubelet
// refreshes a projected service account token and when the original token expires.
// Default token lifetime is 10 minutes, and the kubelet starts refreshing at 80% of lifetime.
// This should induce re-reading at a frequency that works with the token volume source.
period: time.Minute,
},
}
}
type tokenSourceTransport struct {
base http.RoundTripper
ort http.RoundTripper
}
func (tst *tokenSourceTransport) RoundTrip(req *http.Request) (*http.Response, error) {
// This is to allow --token to override other bearer token providers.
if req.Header.Get("Authorization") != "" {
return tst.base.RoundTrip(req)
}
return tst.ort.RoundTrip(req)
}
type fileTokenSource struct {
path string
period time.Duration
}
var _ = oauth2.TokenSource(&fileTokenSource{})
func (ts *fileTokenSource) Token() (*oauth2.Token, error) {
tokb, err := ioutil.ReadFile(ts.path)
if err != nil {
return nil, fmt.Errorf("failed to read token file %q: %v", ts.path, err)
}
tok := strings.TrimSpace(string(tokb))
if len(tok) == 0 {
return nil, fmt.Errorf("read empty token from file %q", ts.path)
}
return &oauth2.Token{
AccessToken: tok,
Expiry: time.Now().Add(ts.period),
}, nil
}
type cachingTokenSource struct {
base oauth2.TokenSource
leeway time.Duration
sync.RWMutex
tok *oauth2.Token
// for testing
now func() time.Time
}
var _ = oauth2.TokenSource(&cachingTokenSource{})
func (ts *cachingTokenSource) Token() (*oauth2.Token, error) {
now := ts.now()
// fast path
ts.RLock()
tok := ts.tok
ts.RUnlock()
if tok != nil && tok.Expiry.Add(-1*ts.leeway).After(now) {
return tok, nil
}
// slow path
ts.Lock()
defer ts.Unlock()
if tok := ts.tok; tok != nil && tok.Expiry.Add(-1*ts.leeway).After(now) {
return tok, nil
}
tok, err := ts.base.Token()
if err != nil {
if ts.tok == nil {
return nil, err
}
klog.Errorf("Unable to rotate token: %v", err)
return ts.tok, nil
}
ts.tok = tok
return tok, nil
}