mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	Expose the constants in pkg/controller/bootstrap and add a validate token method
This commit is contained in:
		| @@ -45,4 +45,13 @@ const ( | ||||
| 	// sign configs as part of the bootstrap process. Value must be "true". Any | ||||
| 	// other value is assumed to be false. Optional. | ||||
| 	BootstrapTokenUsageSigningKey = "usage-bootstrap-signing" | ||||
|  | ||||
| 	// ConfigMapClusterInfo defines the name for the ConfigMap where the information how to connect and trust the cluster exist | ||||
| 	ConfigMapClusterInfo = "cluster-info" | ||||
|  | ||||
| 	// KubeConfigKey defines at which key in the Data object of the ConfigMap the KubeConfig object is stored | ||||
| 	KubeConfigKey = "kubeconfig" | ||||
|  | ||||
| 	// JWSSignatureKeyPrefix defines what key prefix the JWS-signed tokens have | ||||
| 	JWSSignatureKeyPrefix = "jws-kubeconfig-" | ||||
| ) | ||||
|   | ||||
| @@ -38,12 +38,6 @@ import ( | ||||
| 	"k8s.io/kubernetes/pkg/util/metrics" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	configMapClusterInfo = "cluster-info" | ||||
| 	kubeConfigKey        = "kubeconfig" | ||||
| 	signaturePrefix      = "jws-kubeconfig-" | ||||
| ) | ||||
|  | ||||
| // BootstrapSignerOptions contains options for the BootstrapSigner | ||||
| type BootstrapSignerOptions struct { | ||||
|  | ||||
| @@ -70,7 +64,7 @@ type BootstrapSignerOptions struct { | ||||
| func DefaultBootstrapSignerOptions() BootstrapSignerOptions { | ||||
| 	return BootstrapSignerOptions{ | ||||
| 		ConfigMapNamespace:   api.NamespacePublic, | ||||
| 		ConfigMapName:        configMapClusterInfo, | ||||
| 		ConfigMapName:        bootstrapapi.ConfigMapClusterInfo, | ||||
| 		TokenSecretNamespace: api.NamespaceSystem, | ||||
| 	} | ||||
| } | ||||
| @@ -191,17 +185,17 @@ func (e *BootstrapSigner) signConfigMap() { | ||||
| 	} | ||||
|  | ||||
| 	// First capture the config we are signing | ||||
| 	content, ok := newCM.Data[kubeConfigKey] | ||||
| 	content, ok := newCM.Data[bootstrapapi.KubeConfigKey] | ||||
| 	if !ok { | ||||
| 		glog.V(3).Infof("No %s key in %s/%s ConfigMap", kubeConfigKey, origCM.Namespace, origCM.Name) | ||||
| 		glog.V(3).Infof("No %s key in %s/%s ConfigMap", bootstrapapi.KubeConfigKey, origCM.Namespace, origCM.Name) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Next remove and save all existing signatures | ||||
| 	sigs := map[string]string{} | ||||
| 	for key, value := range newCM.Data { | ||||
| 		if strings.HasPrefix(key, signaturePrefix) { | ||||
| 			tokenID := strings.TrimPrefix(key, signaturePrefix) | ||||
| 		if strings.HasPrefix(key, bootstrapapi.JWSSignatureKeyPrefix) { | ||||
| 			tokenID := strings.TrimPrefix(key, bootstrapapi.JWSSignatureKeyPrefix) | ||||
| 			sigs[tokenID] = value | ||||
| 			delete(newCM.Data, key) | ||||
| 		} | ||||
| @@ -222,7 +216,7 @@ func (e *BootstrapSigner) signConfigMap() { | ||||
| 		} | ||||
| 		delete(sigs, tokenID) | ||||
|  | ||||
| 		newCM.Data[signaturePrefix+tokenID] = sig | ||||
| 		newCM.Data[bootstrapapi.JWSSignatureKeyPrefix+tokenID] = sig | ||||
| 	} | ||||
|  | ||||
| 	// If we have signatures left over we know that some signatures were | ||||
|   | ||||
| @@ -27,6 +27,7 @@ import ( | ||||
| 	"k8s.io/client-go/pkg/api" | ||||
| 	"k8s.io/client-go/pkg/api/v1" | ||||
| 	core "k8s.io/client-go/testing" | ||||
| 	bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| @@ -43,15 +44,15 @@ func newConfigMap(tokenID, signature string) *v1.ConfigMap { | ||||
| 	ret := &v1.ConfigMap{ | ||||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Namespace:       metav1.NamespacePublic, | ||||
| 			Name:            configMapClusterInfo, | ||||
| 			Name:            bootstrapapi.ConfigMapClusterInfo, | ||||
| 			ResourceVersion: "1", | ||||
| 		}, | ||||
| 		Data: map[string]string{ | ||||
| 			kubeConfigKey: "payload", | ||||
| 			bootstrapapi.KubeConfigKey: "payload", | ||||
| 		}, | ||||
| 	} | ||||
| 	if len(tokenID) > 0 { | ||||
| 		ret.Data[signaturePrefix+tokenID] = signature | ||||
| 		ret.Data[bootstrapapi.JWSSignatureKeyPrefix+tokenID] = signature | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|   | ||||
| @@ -34,17 +34,17 @@ func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) { | ||||
|  | ||||
| 	signer, err := jose.NewSigner(jose.HS256, jwk) | ||||
| 	if err != nil { | ||||
| 		return "", nil | ||||
| 		return "", fmt.Errorf("can't make a HS256 signer from the given token: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	jws, err := signer.Sign([]byte(content)) | ||||
| 	if err != nil { | ||||
| 		return "", nil | ||||
| 		return "", fmt.Errorf("can't HS256-sign the given token: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	fullSig, err := jws.CompactSerialize() | ||||
| 	if err != nil { | ||||
| 		return "", nil | ||||
| 		return "", fmt.Errorf("can't serialize the given token: %v", err) | ||||
| 	} | ||||
| 	return stripContent(fullSig) | ||||
| } | ||||
| @@ -57,8 +57,17 @@ func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) { | ||||
| func stripContent(fullSig string) (string, error) { | ||||
| 	parts := strings.Split(fullSig, ".") | ||||
| 	if len(parts) != 3 { | ||||
| 		return "", fmt.Errorf("Compact JWS format must have three parts") | ||||
| 		return "", fmt.Errorf("compact JWS format must have three parts") | ||||
| 	} | ||||
|  | ||||
| 	return parts[0] + ".." + parts[2], nil | ||||
| } | ||||
|  | ||||
| // DetachedTokenIsValid checks whether a given detached JWS-encoded token matches JWS output of the given content and token | ||||
| func DetachedTokenIsValid(detachedToken, content, tokenID, tokenSecret string) bool { | ||||
| 	newToken, err := computeDetachedSig(content, tokenID, tokenSecret) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return detachedToken == newToken | ||||
| } | ||||
|   | ||||
| @@ -51,3 +51,17 @@ func TestComputeDetachedSig(t *testing.T) { | ||||
| 		t.Errorf("Wrong signature. Got: %v", sig) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDetachedTokenIsValid(t *testing.T) { | ||||
| 	// Valid detached JWS token and valid inputs should succeed | ||||
| 	sig := "eyJhbGciOiJIUzI1NiIsImtpZCI6Impvc2h1YSJ9..VShe2taLd-YTrmWuRkcL_8QTNDHYxQIEBsAYYiIj1_8" | ||||
| 	if !DetachedTokenIsValid(sig, content, id, secret) { | ||||
| 		t.Errorf("Content %q and token \"%s:%s\" should equal signature: %q", content, id, secret, sig) | ||||
| 	} | ||||
|  | ||||
| 	// Invalid detached JWS token and valid inputs should fail | ||||
| 	sig2 := sig + "foo" | ||||
| 	if DetachedTokenIsValid(sig2, content, id, secret) { | ||||
| 		t.Errorf("Content %q and token \"%s:%s\" should not equal signature: %q", content, id, secret, sig) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user