mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +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
 | 
						// sign configs as part of the bootstrap process. Value must be "true". Any
 | 
				
			||||||
	// other value is assumed to be false. Optional.
 | 
						// other value is assumed to be false. Optional.
 | 
				
			||||||
	BootstrapTokenUsageSigningKey = "usage-bootstrap-signing"
 | 
						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"
 | 
						"k8s.io/kubernetes/pkg/util/metrics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	configMapClusterInfo = "cluster-info"
 | 
					 | 
				
			||||||
	kubeConfigKey        = "kubeconfig"
 | 
					 | 
				
			||||||
	signaturePrefix      = "jws-kubeconfig-"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// BootstrapSignerOptions contains options for the BootstrapSigner
 | 
					// BootstrapSignerOptions contains options for the BootstrapSigner
 | 
				
			||||||
type BootstrapSignerOptions struct {
 | 
					type BootstrapSignerOptions struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,7 +64,7 @@ type BootstrapSignerOptions struct {
 | 
				
			|||||||
func DefaultBootstrapSignerOptions() BootstrapSignerOptions {
 | 
					func DefaultBootstrapSignerOptions() BootstrapSignerOptions {
 | 
				
			||||||
	return BootstrapSignerOptions{
 | 
						return BootstrapSignerOptions{
 | 
				
			||||||
		ConfigMapNamespace:   api.NamespacePublic,
 | 
							ConfigMapNamespace:   api.NamespacePublic,
 | 
				
			||||||
		ConfigMapName:        configMapClusterInfo,
 | 
							ConfigMapName:        bootstrapapi.ConfigMapClusterInfo,
 | 
				
			||||||
		TokenSecretNamespace: api.NamespaceSystem,
 | 
							TokenSecretNamespace: api.NamespaceSystem,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -191,17 +185,17 @@ func (e *BootstrapSigner) signConfigMap() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// First capture the config we are signing
 | 
						// First capture the config we are signing
 | 
				
			||||||
	content, ok := newCM.Data[kubeConfigKey]
 | 
						content, ok := newCM.Data[bootstrapapi.KubeConfigKey]
 | 
				
			||||||
	if !ok {
 | 
						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
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Next remove and save all existing signatures
 | 
						// Next remove and save all existing signatures
 | 
				
			||||||
	sigs := map[string]string{}
 | 
						sigs := map[string]string{}
 | 
				
			||||||
	for key, value := range newCM.Data {
 | 
						for key, value := range newCM.Data {
 | 
				
			||||||
		if strings.HasPrefix(key, signaturePrefix) {
 | 
							if strings.HasPrefix(key, bootstrapapi.JWSSignatureKeyPrefix) {
 | 
				
			||||||
			tokenID := strings.TrimPrefix(key, signaturePrefix)
 | 
								tokenID := strings.TrimPrefix(key, bootstrapapi.JWSSignatureKeyPrefix)
 | 
				
			||||||
			sigs[tokenID] = value
 | 
								sigs[tokenID] = value
 | 
				
			||||||
			delete(newCM.Data, key)
 | 
								delete(newCM.Data, key)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -222,7 +216,7 @@ func (e *BootstrapSigner) signConfigMap() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		delete(sigs, tokenID)
 | 
							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
 | 
						// 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"
 | 
				
			||||||
	"k8s.io/client-go/pkg/api/v1"
 | 
						"k8s.io/client-go/pkg/api/v1"
 | 
				
			||||||
	core "k8s.io/client-go/testing"
 | 
						core "k8s.io/client-go/testing"
 | 
				
			||||||
 | 
						bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@@ -43,15 +44,15 @@ func newConfigMap(tokenID, signature string) *v1.ConfigMap {
 | 
				
			|||||||
	ret := &v1.ConfigMap{
 | 
						ret := &v1.ConfigMap{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Namespace:       metav1.NamespacePublic,
 | 
								Namespace:       metav1.NamespacePublic,
 | 
				
			||||||
			Name:            configMapClusterInfo,
 | 
								Name:            bootstrapapi.ConfigMapClusterInfo,
 | 
				
			||||||
			ResourceVersion: "1",
 | 
								ResourceVersion: "1",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Data: map[string]string{
 | 
							Data: map[string]string{
 | 
				
			||||||
			kubeConfigKey: "payload",
 | 
								bootstrapapi.KubeConfigKey: "payload",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(tokenID) > 0 {
 | 
						if len(tokenID) > 0 {
 | 
				
			||||||
		ret.Data[signaturePrefix+tokenID] = signature
 | 
							ret.Data[bootstrapapi.JWSSignatureKeyPrefix+tokenID] = signature
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ret
 | 
						return ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,17 +34,17 @@ func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	signer, err := jose.NewSigner(jose.HS256, jwk)
 | 
						signer, err := jose.NewSigner(jose.HS256, jwk)
 | 
				
			||||||
	if err != nil {
 | 
						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))
 | 
						jws, err := signer.Sign([]byte(content))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil
 | 
							return "", fmt.Errorf("can't HS256-sign the given token: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fullSig, err := jws.CompactSerialize()
 | 
						fullSig, err := jws.CompactSerialize()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", nil
 | 
							return "", fmt.Errorf("can't serialize the given token: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return stripContent(fullSig)
 | 
						return stripContent(fullSig)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -57,8 +57,17 @@ func computeDetachedSig(content, tokenID, tokenSecret string) (string, error) {
 | 
				
			|||||||
func stripContent(fullSig string) (string, error) {
 | 
					func stripContent(fullSig string) (string, error) {
 | 
				
			||||||
	parts := strings.Split(fullSig, ".")
 | 
						parts := strings.Split(fullSig, ".")
 | 
				
			||||||
	if len(parts) != 3 {
 | 
						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
 | 
						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)
 | 
							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