mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	refactor bootstrap token utils
This commit is contained in:
		@@ -23,20 +23,18 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/klog"
 | 
			
		||||
 | 
			
		||||
	corev1 "k8s.io/api/core/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authentication/authenticator"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authentication/user"
 | 
			
		||||
	corev1listers "k8s.io/client-go/listers/core/v1"
 | 
			
		||||
	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
 | 
			
		||||
	bootstraputil "k8s.io/cluster-bootstrap/token/util"
 | 
			
		||||
	bootstrapsecretutil "k8s.io/cluster-bootstrap/util/secrets"
 | 
			
		||||
	bootstraptokenutil "k8s.io/cluster-bootstrap/util/tokens"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO: A few methods in this package is copied from other sources. Either
 | 
			
		||||
@@ -92,7 +90,7 @@ func tokenErrorf(s *corev1.Secret, format string, i ...interface{}) {
 | 
			
		||||
//     ( token-id ).( token-secret )
 | 
			
		||||
//
 | 
			
		||||
func (t *TokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) {
 | 
			
		||||
	tokenID, tokenSecret, err := parseToken(token)
 | 
			
		||||
	tokenID, tokenSecret, err := bootstraptokenutil.ParseToken(token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Token isn't of the correct form, ignore it.
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
@@ -118,29 +116,29 @@ func (t *TokenAuthenticator) AuthenticateToken(ctx context.Context, token string
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ts := getSecretString(secret, bootstrapapi.BootstrapTokenSecretKey)
 | 
			
		||||
	ts := bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenSecretKey)
 | 
			
		||||
	if subtle.ConstantTimeCompare([]byte(ts), []byte(tokenSecret)) != 1 {
 | 
			
		||||
		tokenErrorf(secret, "has invalid value for key %s, expected %s.", bootstrapapi.BootstrapTokenSecretKey, tokenSecret)
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id := getSecretString(secret, bootstrapapi.BootstrapTokenIDKey)
 | 
			
		||||
	id := bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenIDKey)
 | 
			
		||||
	if id != tokenID {
 | 
			
		||||
		tokenErrorf(secret, "has invalid value for key %s, expected %s.", bootstrapapi.BootstrapTokenIDKey, tokenID)
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isSecretExpired(secret) {
 | 
			
		||||
	if bootstrapsecretutil.HasExpired(secret, time.Now()) {
 | 
			
		||||
		// logging done in isSecretExpired method.
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if getSecretString(secret, bootstrapapi.BootstrapTokenUsageAuthentication) != "true" {
 | 
			
		||||
	if bootstrapsecretutil.GetData(secret, bootstrapapi.BootstrapTokenUsageAuthentication) != "true" {
 | 
			
		||||
		tokenErrorf(secret, "not marked %s=true.", bootstrapapi.BootstrapTokenUsageAuthentication)
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	groups, err := getGroups(secret)
 | 
			
		||||
	groups, err := bootstrapsecretutil.GetGroups(secret)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		tokenErrorf(secret, "has invalid value for key %s: %v.", bootstrapapi.BootstrapTokenExtraGroupsKey, err)
 | 
			
		||||
		return nil, false, nil
 | 
			
		||||
@@ -153,76 +151,3 @@ func (t *TokenAuthenticator) AuthenticateToken(ctx context.Context, token string
 | 
			
		||||
		},
 | 
			
		||||
	}, true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copied from k8s.io/cluster-bootstrap/token/api
 | 
			
		||||
func getSecretString(secret *corev1.Secret, key string) string {
 | 
			
		||||
	data, ok := secret.Data[key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return string(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copied from k8s.io/cluster-bootstrap/token/api
 | 
			
		||||
func isSecretExpired(secret *corev1.Secret) bool {
 | 
			
		||||
	expiration := getSecretString(secret, bootstrapapi.BootstrapTokenExpirationKey)
 | 
			
		||||
	if len(expiration) > 0 {
 | 
			
		||||
		expTime, err2 := time.Parse(time.RFC3339, expiration)
 | 
			
		||||
		if err2 != nil {
 | 
			
		||||
			klog.V(3).Infof("Unparseable expiration time (%s) in %s/%s Secret: %v. Treating as expired.",
 | 
			
		||||
				expiration, secret.Namespace, secret.Name, err2)
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if time.Now().After(expTime) {
 | 
			
		||||
			klog.V(3).Infof("Expired bootstrap token in %s/%s Secret: %v",
 | 
			
		||||
				secret.Namespace, secret.Name, expiration)
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copied from kubernetes/cmd/kubeadm/app/util/token
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// tokenRegexpString defines id.secret regular expression pattern
 | 
			
		||||
	tokenRegexpString = "^([a-z0-9]{6})\\.([a-z0-9]{16})$"
 | 
			
		||||
	// tokenRegexp is a compiled regular expression of TokenRegexpString
 | 
			
		||||
	tokenRegexp = regexp.MustCompile(tokenRegexpString)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// parseToken tries and parse a valid token from a string.
 | 
			
		||||
// A token ID and token secret are returned in case of success, an error otherwise.
 | 
			
		||||
func parseToken(s string) (string, string, error) {
 | 
			
		||||
	split := tokenRegexp.FindStringSubmatch(s)
 | 
			
		||||
	if len(split) != 3 {
 | 
			
		||||
		return "", "", fmt.Errorf("token [%q] was not of form [%q]", s, tokenRegexpString)
 | 
			
		||||
	}
 | 
			
		||||
	return split[1], split[2], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getGroups loads and validates the bootstrapapi.BootstrapTokenExtraGroupsKey
 | 
			
		||||
// key from the bootstrap token secret, returning a list of group names or an
 | 
			
		||||
// error if any of the group names are invalid.
 | 
			
		||||
func getGroups(secret *corev1.Secret) ([]string, error) {
 | 
			
		||||
	// always include the default group
 | 
			
		||||
	groups := sets.NewString(bootstrapapi.BootstrapDefaultGroup)
 | 
			
		||||
 | 
			
		||||
	// grab any extra groups and if there are none, return just the default
 | 
			
		||||
	extraGroupsString := getSecretString(secret, bootstrapapi.BootstrapTokenExtraGroupsKey)
 | 
			
		||||
	if extraGroupsString == "" {
 | 
			
		||||
		return groups.List(), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// validate the names of the extra groups
 | 
			
		||||
	for _, group := range strings.Split(extraGroupsString, ",") {
 | 
			
		||||
		if err := bootstraputil.ValidateBootstrapGroupName(group); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		groups.Insert(group)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// return the result as a deduplicated, sorted list
 | 
			
		||||
	return groups.List(), nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user