Merge pull request #53929 from wackxu/valuse

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Validate usage strings when creating bootstrap tokens via kubeadm

**What this PR does / why we need it**:

fix TODO: Validate usages here so we don't allow something unsupported

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2017-11-18 15:31:28 -08:00 committed by GitHub
commit 5653b69bee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 7 deletions

View File

@ -218,6 +218,11 @@ func RunCreateToken(out io.Writer, client clientset.Interface, token string, tok
}
}
// validate usages
if err := bootstrapapi.ValidateUsages(usages); err != nil {
return err
}
err := tokenphase.CreateNewToken(client, token, tokenDuration, usages, extraGroups, description)
if err != nil {
return err

View File

@ -53,7 +53,11 @@ func UpdateOrCreateToken(client clientset.Interface, token string, failIfExists
return fmt.Errorf("a token with id %q already exists", tokenID)
}
// Secret with this ID already exists, update it:
secret.Data = encodeTokenSecretData(tokenID, tokenSecret, tokenDuration, usages, extraGroups, description)
tokenSecretData, err := encodeTokenSecretData(tokenID, tokenSecret, tokenDuration, usages, extraGroups, description)
if err != nil {
return err
}
secret.Data = tokenSecretData
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Update(secret); err == nil {
return nil
}
@ -63,12 +67,17 @@ func UpdateOrCreateToken(client clientset.Interface, token string, failIfExists
// Secret does not already exist:
if apierrors.IsNotFound(err) {
tokenSecretData, err := encodeTokenSecretData(tokenID, tokenSecret, tokenDuration, usages, extraGroups, description)
if err != nil {
return err
}
secret = &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
},
Type: v1.SecretType(bootstrapapi.SecretTypeBootstrapToken),
Data: encodeTokenSecretData(tokenID, tokenSecret, tokenDuration, usages, extraGroups, description),
Data: tokenSecretData,
}
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err == nil {
return nil
@ -86,7 +95,7 @@ func UpdateOrCreateToken(client clientset.Interface, token string, failIfExists
}
// encodeTokenSecretData takes the token discovery object and an optional duration and returns the .Data for the Secret
func encodeTokenSecretData(tokenID, tokenSecret string, duration time.Duration, usages []string, extraGroups []string, description string) map[string][]byte {
func encodeTokenSecretData(tokenID, tokenSecret string, duration time.Duration, usages []string, extraGroups []string, description string) (map[string][]byte, error) {
data := map[string][]byte{
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
@ -104,9 +113,13 @@ func encodeTokenSecretData(tokenID, tokenSecret string, duration time.Duration,
if len(description) > 0 {
data[bootstrapapi.BootstrapTokenDescriptionKey] = []byte(description)
}
// validate usages
if err := bootstrapapi.ValidateUsages(usages); err != nil {
return nil, err
}
for _, usage := range usages {
// TODO: Validate the usage string here before
data[bootstrapapi.BootstrapTokenUsagePrefix+usage] = []byte("true")
}
return data
return data, nil
}

View File

@ -33,7 +33,7 @@ func TestEncodeTokenSecretData(t *testing.T) {
{token: &kubeadmapi.TokenDiscovery{ID: "foo", Secret: "bar"}, t: time.Second}, // should use default
}
for _, rt := range tests {
actual := encodeTokenSecretData(rt.token.ID, rt.token.Secret, rt.t, []string{}, []string{}, "")
actual, _ := encodeTokenSecretData(rt.token.ID, rt.token.Secret, rt.t, []string{}, []string{}, "")
if !bytes.Equal(actual["token-id"], []byte(rt.token.ID)) {
t.Errorf(
"failed EncodeTokenSecretData:\n\texpected: %s\n\t actual: %s",

View File

@ -14,7 +14,10 @@ go_library(
"types.go",
],
importpath = "k8s.io/kubernetes/pkg/bootstrap/api",
deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
deps = [
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(

View File

@ -18,7 +18,9 @@ package api
import (
"fmt"
"k8s.io/apimachinery/pkg/util/sets"
"regexp"
"strings"
)
var bootstrapGroupRegexp = regexp.MustCompile(`\A` + BootstrapGroupPattern + `\z`)
@ -32,3 +34,19 @@ func ValidateBootstrapGroupName(name string) error {
}
return fmt.Errorf("bootstrap group %q is invalid (must match %s)", name, BootstrapGroupPattern)
}
// ValidateUsages validates that the passed in string are valid usage strings for bootstrap tokens.
func ValidateUsages(usages []string) error {
usageAuthentication := strings.TrimPrefix(BootstrapTokenUsageAuthentication, BootstrapTokenUsagePrefix)
usageSigning := strings.TrimPrefix(BootstrapTokenUsageSigningKey, BootstrapTokenUsagePrefix)
invalidUsages := sets.NewString()
for _, usage := range usages {
if usage != usageAuthentication && usage != usageSigning {
invalidUsages.Insert(usage)
}
}
if len(invalidUsages) > 0 {
return fmt.Errorf("invalide bootstrap token usage string: %s, valid usage option: %s, %s", strings.Join(invalidUsages.List(), ","), usageAuthentication, usageSigning)
}
return nil
}

View File

@ -50,3 +50,27 @@ func TestValidateBootstrapGroupName(t *testing.T) {
}
}
}
func TestValidateUsages(t *testing.T) {
tests := []struct {
name string
input []string
valid bool
}{
{"valid of signing", []string{"signing"}, true},
{"valid of authentication", []string{"authentication"}, true},
{"all valid", []string{"authentication", "signing"}, true},
{"single invalid", []string{"authentication", "foo"}, false},
{"all invalid", []string{"foo", "bar"}, false},
}
for _, test := range tests {
err := ValidateUsages(test.input)
if err != nil && test.valid {
t.Errorf("test %q: ValidateUsages(%v) returned unexpected error: %v", test.name, test.input, err)
}
if err == nil && !test.valid {
t.Errorf("test %q: ValidateUsages(%v) was supposed to return an error but didn't", test.name, test.input)
}
}
}