mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
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:
commit
5653b69bee
@ -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)
|
err := tokenphase.CreateNewToken(client, token, tokenDuration, usages, extraGroups, description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -53,7 +53,11 @@ func UpdateOrCreateToken(client clientset.Interface, token string, failIfExists
|
|||||||
return fmt.Errorf("a token with id %q already exists", tokenID)
|
return fmt.Errorf("a token with id %q already exists", tokenID)
|
||||||
}
|
}
|
||||||
// Secret with this ID already exists, update it:
|
// 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 {
|
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Update(secret); err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -63,12 +67,17 @@ func UpdateOrCreateToken(client clientset.Interface, token string, failIfExists
|
|||||||
|
|
||||||
// Secret does not already exist:
|
// Secret does not already exist:
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
|
tokenSecretData, err := encodeTokenSecretData(tokenID, tokenSecret, tokenDuration, usages, extraGroups, description)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
secret = &v1.Secret{
|
secret = &v1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: secretName,
|
Name: secretName,
|
||||||
},
|
},
|
||||||
Type: v1.SecretType(bootstrapapi.SecretTypeBootstrapToken),
|
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 {
|
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err == nil {
|
||||||
return 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
|
// 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{
|
data := map[string][]byte{
|
||||||
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
|
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
|
||||||
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
|
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
|
||||||
@ -104,9 +113,13 @@ func encodeTokenSecretData(tokenID, tokenSecret string, duration time.Duration,
|
|||||||
if len(description) > 0 {
|
if len(description) > 0 {
|
||||||
data[bootstrapapi.BootstrapTokenDescriptionKey] = []byte(description)
|
data[bootstrapapi.BootstrapTokenDescriptionKey] = []byte(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate usages
|
||||||
|
if err := bootstrapapi.ValidateUsages(usages); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
for _, usage := range usages {
|
for _, usage := range usages {
|
||||||
// TODO: Validate the usage string here before
|
|
||||||
data[bootstrapapi.BootstrapTokenUsagePrefix+usage] = []byte("true")
|
data[bootstrapapi.BootstrapTokenUsagePrefix+usage] = []byte("true")
|
||||||
}
|
}
|
||||||
return data
|
return data, nil
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func TestEncodeTokenSecretData(t *testing.T) {
|
|||||||
{token: &kubeadmapi.TokenDiscovery{ID: "foo", Secret: "bar"}, t: time.Second}, // should use default
|
{token: &kubeadmapi.TokenDiscovery{ID: "foo", Secret: "bar"}, t: time.Second}, // should use default
|
||||||
}
|
}
|
||||||
for _, rt := range tests {
|
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)) {
|
if !bytes.Equal(actual["token-id"], []byte(rt.token.ID)) {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"failed EncodeTokenSecretData:\n\texpected: %s\n\t actual: %s",
|
"failed EncodeTokenSecretData:\n\texpected: %s\n\t actual: %s",
|
||||||
|
@ -14,7 +14,10 @@ go_library(
|
|||||||
"types.go",
|
"types.go",
|
||||||
],
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/bootstrap/api",
|
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(
|
filegroup(
|
||||||
|
@ -18,7 +18,9 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bootstrapGroupRegexp = regexp.MustCompile(`\A` + BootstrapGroupPattern + `\z`)
|
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)
|
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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user