diff --git a/hack/.linted_packages b/hack/.linted_packages index f3ef847cdf6..71fc2db171b 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -86,6 +86,7 @@ pkg/apis/settings/install pkg/apis/settings/validation pkg/apis/storage/install pkg/apis/storage/validation +pkg/auth/nodeidentifier pkg/bootstrap/api pkg/client/conditions pkg/client/informers/informers_generated/externalversions diff --git a/pkg/BUILD b/pkg/BUILD index 83cd2a523df..2f5f692342c 100644 --- a/pkg/BUILD +++ b/pkg/BUILD @@ -31,6 +31,7 @@ filegroup( "//pkg/apis/settings:all-srcs", "//pkg/apis/storage:all-srcs", "//pkg/auth/authorizer/abac:all-srcs", + "//pkg/auth/nodeidentifier:all-srcs", "//pkg/auth/user:all-srcs", "//pkg/bootstrap/api:all-srcs", "//pkg/capabilities:all-srcs", diff --git a/pkg/auth/nodeidentifier/BUILD b/pkg/auth/nodeidentifier/BUILD new file mode 100644 index 00000000000..cc228ad79c1 --- /dev/null +++ b/pkg/auth/nodeidentifier/BUILD @@ -0,0 +1,40 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = [ + "default.go", + "interfaces.go", + ], + tags = ["automanaged"], + deps = ["//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library"], +) + +go_test( + name = "go_default_test", + srcs = ["default_test.go"], + library = ":go_default_library", + tags = ["automanaged"], + deps = ["//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/pkg/auth/nodeidentifier/default.go b/pkg/auth/nodeidentifier/default.go new file mode 100644 index 00000000000..80df38ba4f3 --- /dev/null +++ b/pkg/auth/nodeidentifier/default.go @@ -0,0 +1,64 @@ +/* +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 nodeidentifier + +import ( + "strings" + + "k8s.io/apiserver/pkg/authentication/user" +) + +// NewDefaultNodeIdentifier returns a default NodeIdentifier implementation, +// which returns isNode=true if the user groups contain the system:nodes group, +// and populates nodeName if isNode is true, and the user name is in the format system:node: +func NewDefaultNodeIdentifier() NodeIdentifier { + return defaultNodeIdentifier{} +} + +// defaultNodeIdentifier implements NodeIdentifier +type defaultNodeIdentifier struct{} + +// nodeUserNamePrefix is the prefix for usernames in the form `system:node:` +const nodeUserNamePrefix = "system:node:" + +// NodeIdentity returns isNode=true if the user groups contain the system:nodes group, +// and populates nodeName if isNode is true, and the user name is in the format system:node: +func (defaultNodeIdentifier) NodeIdentity(u user.Info) (string, bool) { + // Make sure we're a node, and can parse the node name + if u == nil { + return "", false + } + + isNode := false + for _, g := range u.GetGroups() { + if g == user.NodesGroup { + isNode = true + break + } + } + if !isNode { + return "", false + } + + userName := u.GetName() + nodeName := "" + if strings.HasPrefix(userName, nodeUserNamePrefix) { + nodeName = strings.TrimPrefix(userName, nodeUserNamePrefix) + } + + return nodeName, isNode +} diff --git a/pkg/auth/nodeidentifier/default_test.go b/pkg/auth/nodeidentifier/default_test.go new file mode 100644 index 00000000000..fee38d57296 --- /dev/null +++ b/pkg/auth/nodeidentifier/default_test.go @@ -0,0 +1,68 @@ +/* +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 nodeidentifier + +import ( + "testing" + + "k8s.io/apiserver/pkg/authentication/user" +) + +func TestDefaultNodeIdentifier_NodeIdentity(t *testing.T) { + tests := []struct { + name string + user user.Info + expectNodeName string + expectIsNode bool + }{ + { + name: "nil user", + user: nil, + expectNodeName: "", + expectIsNode: false, + }, + { + name: "node username without group", + user: &user.DefaultInfo{Name: "system:node:foo"}, + expectNodeName: "", + expectIsNode: false, + }, + { + name: "node group without username", + user: &user.DefaultInfo{Name: "foo", Groups: []string{"system:nodes"}}, + expectNodeName: "", + expectIsNode: true, + }, + { + name: "node group and username", + user: &user.DefaultInfo{Name: "system:node:foo", Groups: []string{"system:nodes"}}, + expectNodeName: "foo", + expectIsNode: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nodeName, isNode := NewDefaultNodeIdentifier().NodeIdentity(tt.user) + if nodeName != tt.expectNodeName { + t.Errorf("DefaultNodeIdentifier.NodeIdentity() got = %v, want %v", nodeName, tt.expectNodeName) + } + if isNode != tt.expectIsNode { + t.Errorf("DefaultNodeIdentifier.NodeIdentity() got1 = %v, want %v", isNode, tt.expectIsNode) + } + }) + } +} diff --git a/pkg/auth/nodeidentifier/interfaces.go b/pkg/auth/nodeidentifier/interfaces.go new file mode 100644 index 00000000000..917bebaf9d9 --- /dev/null +++ b/pkg/auth/nodeidentifier/interfaces.go @@ -0,0 +1,30 @@ +/* +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 nodeidentifier + +import ( + "k8s.io/apiserver/pkg/authentication/user" +) + +// NodeIdentifier determines node information from a given user +type NodeIdentifier interface { + // IdentifyNode determines node information from the given user.Info. + // nodeName is the name of the Node API object associated with the user.Info, + // and may be empty if a specific node cannot be determined. + // isNode is true if the user.Info represents an identity issued to a node. + NodeIdentity(user.Info) (nodeName string, isNode bool) +}