Skip to content

Commit

Permalink
Merge pull request #41385 from luxas/extend_token_bootstrap
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue (batch tested with PRs 41378, 41413, 40743, 41155, 41385)

Expose the constants in pkg/controller/bootstrap and add a validate token function

**What this PR does / why we need it**: In order to hook up #36101 against kubeadm, we have to expose the constants and add a function to validate the token

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
cc @jbeda @mikedanese @pires @dmmcquay
  • Loading branch information
Kubernetes Submit Queue committed Feb 15, 2017
2 parents ef04245 + 4940c32 commit 4faa1e4
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 19 deletions.
9 changes: 9 additions & 0 deletions pkg/bootstrap/api/types.go
Expand Up @@ -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-"
)
18 changes: 6 additions & 12 deletions pkg/controller/bootstrap/bootstrapsigner.go
Expand Up @@ -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 {

Expand All @@ -70,7 +64,7 @@ type BootstrapSignerOptions struct {
func DefaultBootstrapSignerOptions() BootstrapSignerOptions {
return BootstrapSignerOptions{
ConfigMapNamespace: api.NamespacePublic,
ConfigMapName: configMapClusterInfo,
ConfigMapName: bootstrapapi.ConfigMapClusterInfo,
TokenSecretNamespace: api.NamespaceSystem,
}
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions pkg/controller/bootstrap/bootstrapsigner_test.go
Expand Up @@ -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() {
Expand All @@ -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
}
Expand Down
17 changes: 13 additions & 4 deletions pkg/controller/bootstrap/jws.go
Expand Up @@ -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)
}
Expand All @@ -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
}
14 changes: 14 additions & 0 deletions pkg/controller/bootstrap/jws_test.go
Expand Up @@ -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)
}
}

0 comments on commit 4faa1e4

Please sign in to comment.