diff --git a/pkg/bootstrap/api/BUILD b/pkg/bootstrap/api/BUILD index dfb7d697638..db7be057bf6 100644 --- a/pkg/bootstrap/api/BUILD +++ b/pkg/bootstrap/api/BUILD @@ -3,12 +3,14 @@ package(default_visibility = ["//visibility:public"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( name = "go_default_library", srcs = [ "doc.go", + "helpers.go", "types.go", ], deps = ["//vendor/k8s.io/api/core/v1:go_default_library"], @@ -26,3 +28,9 @@ filegroup( srcs = [":package-srcs"], tags = ["automanaged"], ) + +go_test( + name = "go_default_test", + srcs = ["helpers_test.go"], + library = ":go_default_library", +) diff --git a/pkg/bootstrap/api/helpers.go b/pkg/bootstrap/api/helpers.go new file mode 100644 index 00000000000..639d61a33c3 --- /dev/null +++ b/pkg/bootstrap/api/helpers.go @@ -0,0 +1,34 @@ +/* +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 ( + "fmt" + "regexp" +) + +var bootstrapGroupRegexp = regexp.MustCompile(`\A` + 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, BootstrapGroupPattern) +} diff --git a/pkg/bootstrap/api/helpers_test.go b/pkg/bootstrap/api/helpers_test.go new file mode 100644 index 00000000000..177687150c5 --- /dev/null +++ b/pkg/bootstrap/api/helpers_test.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 api + +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) + } + } +} diff --git a/pkg/bootstrap/api/types.go b/pkg/bootstrap/api/types.go index a7cca0c9bd8..a4e67a1c249 100644 --- a/pkg/bootstrap/api/types.go +++ b/pkg/bootstrap/api/types.go @@ -51,6 +51,11 @@ const ( // 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-" @@ -63,7 +68,8 @@ const ( // 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 group "system:bootstrappers". + // 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" @@ -80,6 +86,12 @@ const ( // authenticate as. The full username given is "system:bootstrap:". BootstrapUserPrefix = "system:bootstrap:" - // BootstrapGroup is the group bootstrapping bearer tokens authenticate in. - BootstrapGroup = "system:bootstrappers" + // 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" ) diff --git a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go b/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go index 62b3ad50d8c..abd5eb196f2 100644 --- a/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go +++ b/plugin/pkg/auth/authenticator/token/bootstrap/bootstrap.go @@ -136,7 +136,7 @@ func (t *TokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, e return &user.DefaultInfo{ Name: bootstrapapi.BootstrapUserPrefix + string(id), - Groups: []string{bootstrapapi.BootstrapGroup}, + Groups: []string{bootstrapapi.BootstrapDefaultGroup}, }, true, nil }