From 01f7f3801f948e1011ba145bb475991a56bfc976 Mon Sep 17 00:00:00 2001
From: Gavin
Date: Wed, 17 Jan 2018 16:22:37 +0800
Subject: [PATCH] Add generic Bootstrap Token constants and helpers to
client-go
Kubernetes-commit: bb5e156aba3ff73ceb85576670c35d7565b84a4c
---
tools/bootstrap/token/api/doc.go | 20 +++++
tools/bootstrap/token/api/types.go | 100 +++++++++++++++++++++
tools/bootstrap/token/util/helpers.go | 52 +++++++++++
tools/bootstrap/token/util/helpers_test.go | 76 ++++++++++++++++
4 files changed, 248 insertions(+)
create mode 100644 tools/bootstrap/token/api/doc.go
create mode 100644 tools/bootstrap/token/api/types.go
create mode 100644 tools/bootstrap/token/util/helpers.go
create mode 100644 tools/bootstrap/token/util/helpers_test.go
diff --git a/tools/bootstrap/token/api/doc.go b/tools/bootstrap/token/api/doc.go
new file mode 100644
index 00000000..72738711
--- /dev/null
+++ b/tools/bootstrap/token/api/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package api (pkg/bootstrap/api) contains constants and types needed for
+// bootstrap tokens as maintained by the BootstrapSigner and TokenCleaner
+// controllers (in pkg/controller/bootstrap)
+package api // import "k8s.io/client-go/tools/bootstrap/api"
diff --git a/tools/bootstrap/token/api/types.go b/tools/bootstrap/token/api/types.go
new file mode 100644
index 00000000..c30814c0
--- /dev/null
+++ b/tools/bootstrap/token/api/types.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package api
+
+import (
+ "k8s.io/api/core/v1"
+)
+
+const (
+ // BootstrapTokenSecretPrefix is the prefix for bootstrap token names.
+ // Bootstrap tokens secrets must be named in the form
+ // `bootstrap-token-`. This is the prefix to be used before the
+ // token ID.
+ BootstrapTokenSecretPrefix = "bootstrap-token-"
+
+ // SecretTypeBootstrapToken is used during the automated bootstrap process (first
+ // implemented by kubeadm). It stores tokens that are used to sign well known
+ // ConfigMaps. They may also eventually be used for authentication.
+ SecretTypeBootstrapToken v1.SecretType = "bootstrap.kubernetes.io/token"
+
+ // BootstrapTokenIDKey is the id of this token. This can be transmitted in the
+ // clear and encoded in the name of the secret. It must be a random 6 character
+ // string that matches the regexp `^([a-z0-9]{6})$`. Required.
+ BootstrapTokenIDKey = "token-id"
+
+ // BootstrapTokenSecretKey is the actual secret. It must be a random 16 character
+ // string that matches the regexp `^([a-z0-9]{16})$`. Required.
+ BootstrapTokenSecretKey = "token-secret"
+
+ // BootstrapTokenExpirationKey is when this token should be expired and no
+ // longer used. A controller will delete this resource after this time. This
+ // is an absolute UTC time using RFC3339. If this cannot be parsed, the token
+ // should be considered invalid. Optional.
+ BootstrapTokenExpirationKey = "expiration"
+
+ // BootstrapTokenDescriptionKey is a description in human-readable format that
+ // describes what the bootstrap token is used for. Optional.
+ BootstrapTokenDescriptionKey = "description"
+
+ // BootstrapTokenExtraGroupsKey is a comma-separated list of group names.
+ // The bootstrap token will authenticate as these groups in addition to the
+ // "system:bootstrappers" group.
+ BootstrapTokenExtraGroupsKey = "auth-extra-groups"
+
+ // BootstrapTokenUsagePrefix is the prefix for the other usage constants that specifies different
+ // functions of a bootstrap token
+ BootstrapTokenUsagePrefix = "usage-bootstrap-"
+
+ // BootstrapTokenUsageSigningKey signals that this token should be used to
+ // 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"
+
+ // BootstrapTokenUsageAuthentication signals that this token should be used
+ // as a bearer token to authenticate against the Kubernetes API. The bearer
+ // token takes the form "." and authenticates as the
+ // user "system:bootstrap:" in the "system:bootstrappers" group
+ // as well as any groups specified using BootstrapTokenExtraGroupsKey.
+ // Value must be "true". Any other value is assumed to be false. Optional.
+ BootstrapTokenUsageAuthentication = "usage-bootstrap-authentication"
+
+ // 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-"
+
+ // BootstrapUserPrefix is the username prefix bootstrapping bearer tokens
+ // authenticate as. The full username given is "system:bootstrap:".
+ BootstrapUserPrefix = "system:bootstrap:"
+
+ // BootstrapGroupPattern is the valid regex pattern that all groups
+ // assigned to a bootstrap token by BootstrapTokenExtraGroupsKey must match.
+ // See also ValidateBootstrapGroupName().
+ BootstrapGroupPattern = "system:bootstrappers:[a-z0-9:-]{0,255}[a-z0-9]"
+
+ // BootstrapDefaultGroup is the default group for bootstrapping bearer
+ // tokens (in addition to any groups from BootstrapTokenExtraGroupsKey).
+ BootstrapDefaultGroup = "system:bootstrappers"
+)
+
+// KnownTokenUsages specifies the known functions a token will get.
+var KnownTokenUsages = []string{"signing", "authentication"}
diff --git a/tools/bootstrap/token/util/helpers.go b/tools/bootstrap/token/util/helpers.go
new file mode 100644
index 00000000..d28fd28f
--- /dev/null
+++ b/tools/bootstrap/token/util/helpers.go
@@ -0,0 +1,52 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+ "fmt"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/client-go/tools/bootstrap/token/api"
+ "regexp"
+ "strings"
+)
+
+var bootstrapGroupRegexp = regexp.MustCompile(`\A` + api.BootstrapGroupPattern + `\z`)
+
+// ValidateBootstrapGroupName checks if the provided group name is a valid
+// bootstrap group name. Returns nil if valid or a validation error if invalid.
+// TODO(mattmoyer): this validation should migrate out to client-go (see https://github.com/kubernetes/client-go/issues/114)
+func ValidateBootstrapGroupName(name string) error {
+ if bootstrapGroupRegexp.Match([]byte(name)) {
+ return nil
+ }
+ return fmt.Errorf("bootstrap group %q is invalid (must match %s)", name, api.BootstrapGroupPattern)
+}
+
+// ValidateUsages validates that the passed in string are valid usage strings for bootstrap tokens.
+func ValidateUsages(usages []string) error {
+ validUsages := sets.NewString(api.KnownTokenUsages...)
+ invalidUsages := sets.NewString()
+ for _, usage := range usages {
+ if !validUsages.Has(usage) {
+ invalidUsages.Insert(usage)
+ }
+ }
+ if len(invalidUsages) > 0 {
+ return fmt.Errorf("invalide bootstrap token usage string: %s, valid usage options: %s", strings.Join(invalidUsages.List(), ","), strings.Join(api.KnownTokenUsages, ","))
+ }
+ return nil
+}
diff --git a/tools/bootstrap/token/util/helpers_test.go b/tools/bootstrap/token/util/helpers_test.go
new file mode 100644
index 00000000..915bf754
--- /dev/null
+++ b/tools/bootstrap/token/util/helpers_test.go
@@ -0,0 +1,76 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestValidateBootstrapGroupName(t *testing.T) {
+ tests := []struct {
+ name string
+ input string
+ valid bool
+ }{
+ {"valid", "system:bootstrappers:foo", true},
+ {"valid nested", "system:bootstrappers:foo:bar:baz", true},
+ {"valid with dashes and number", "system:bootstrappers:foo-bar-42", true},
+ {"invalid uppercase", "system:bootstrappers:Foo", false},
+ {"missing prefix", "foo", false},
+ {"prefix with no body", "system:bootstrappers:", false},
+ {"invalid spaces", "system:bootstrappers: ", false},
+ {"invalid asterisk", "system:bootstrappers:*", false},
+ {"trailing colon", "system:bootstrappers:foo:", false},
+ {"trailing dash", "system:bootstrappers:foo-", false},
+ {"script tags", "system:bootstrappers:", false},
+ {"too long", "system:bootstrappers:" + strings.Repeat("x", 300), false},
+ }
+ for _, test := range tests {
+ err := ValidateBootstrapGroupName(test.input)
+ if err != nil && test.valid {
+ t.Errorf("test %q: ValidateBootstrapGroupName(%q) returned unexpected error: %v", test.name, test.input, err)
+ }
+ if err == nil && !test.valid {
+ t.Errorf("test %q: ValidateBootstrapGroupName(%q) was supposed to return an error but didn't", test.name, test.input)
+ }
+ }
+}
+
+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)
+ }
+ }
+}