mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Implement auth-extra-groups
in bootstrap token authenticator.
This implements support for the new `auth-extra-groups` key in `bootstrap.kubernetes.io/token` secrets by adding extra groups to the user info returned for valid bootstrap tokens.
This commit is contained in:
parent
33e02aff60
commit
fd5c00b38d
@ -30,6 +30,7 @@ go_library(
|
||||
"//pkg/client/listers/core/internalversion:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -23,11 +23,13 @@ import (
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
|
||||
@ -79,6 +81,7 @@ func tokenErrorf(s *api.Secret, format string, i ...interface{}) {
|
||||
// token-id: ( token id )
|
||||
// # Required key usage.
|
||||
// usage-bootstrap-authentication: true
|
||||
// auth-extra-groups: "system:bootstrappers:custom-group1,system:bootstrappers:custom-group2"
|
||||
// # May also contain an expiry.
|
||||
//
|
||||
// Tokens are expected to be of the form:
|
||||
@ -134,9 +137,15 @@ func (t *TokenAuthenticator) AuthenticateToken(token string) (user.Info, bool, e
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
groups, err := getGroups(secret)
|
||||
if err != nil {
|
||||
tokenErrorf(secret, "has invalid value for key %s: %v.", bootstrapapi.BootstrapTokenExtraGroupsKey, err)
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return &user.DefaultInfo{
|
||||
Name: bootstrapapi.BootstrapUserPrefix + string(id),
|
||||
Groups: []string{bootstrapapi.BootstrapDefaultGroup},
|
||||
Groups: groups,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
@ -184,3 +193,28 @@ func parseToken(s string) (string, string, error) {
|
||||
}
|
||||
return split[1], split[2], nil
|
||||
}
|
||||
|
||||
// getGroups loads and validates the bootstrapapi.BootstrapTokenExtraGroupsKey
|
||||
// key from the bootstrap token secret, returning a list of group names or an
|
||||
// error if any of the group names are invalid.
|
||||
func getGroups(secret *api.Secret) ([]string, error) {
|
||||
// always include the default group
|
||||
groups := sets.NewString(bootstrapapi.BootstrapDefaultGroup)
|
||||
|
||||
// grab any extra groups and if there are none, return just the default
|
||||
extraGroupsString := getSecretString(secret, bootstrapapi.BootstrapTokenExtraGroupsKey)
|
||||
if extraGroupsString == "" {
|
||||
return groups.List(), nil
|
||||
}
|
||||
|
||||
// validate the names of the extra groups
|
||||
for _, group := range strings.Split(extraGroupsString, ",") {
|
||||
if err := bootstrapapi.ValidateBootstrapGroupName(group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups.Insert(group)
|
||||
}
|
||||
|
||||
// return the result as a deduplicated, sorted list
|
||||
return groups.List(), nil
|
||||
}
|
||||
|
@ -84,6 +84,47 @@ func TestTokenAuthenticator(t *testing.T) {
|
||||
Groups: []string{"system:bootstrappers"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid token with extra group",
|
||||
secrets: []*api.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
|
||||
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
|
||||
bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
|
||||
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:foo"),
|
||||
},
|
||||
Type: "bootstrap.kubernetes.io/token",
|
||||
},
|
||||
},
|
||||
token: tokenID + "." + tokenSecret,
|
||||
wantUser: &user.DefaultInfo{
|
||||
Name: "system:bootstrap:" + tokenID,
|
||||
Groups: []string{"system:bootstrappers", "system:bootstrappers:foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid group",
|
||||
secrets: []*api.Secret{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: bootstrapapi.BootstrapTokenSecretPrefix + tokenID,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
|
||||
bootstrapapi.BootstrapTokenSecretKey: []byte(tokenSecret),
|
||||
bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
|
||||
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("foo"),
|
||||
},
|
||||
Type: "bootstrap.kubernetes.io/token",
|
||||
},
|
||||
},
|
||||
token: tokenID + "." + tokenSecret,
|
||||
wantNotFound: true,
|
||||
},
|
||||
{
|
||||
name: "invalid secret name",
|
||||
secrets: []*api.Secret{
|
||||
@ -247,3 +288,72 @@ func TestTokenAuthenticator(t *testing.T) {
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGroups(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
secret *api.Secret
|
||||
expectResult []string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "not set",
|
||||
secret: &api.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test"},
|
||||
Data: map[string][]byte{},
|
||||
},
|
||||
expectResult: []string{"system:bootstrappers"},
|
||||
},
|
||||
{
|
||||
name: "set to empty value",
|
||||
secret: &api.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test"},
|
||||
Data: map[string][]byte{
|
||||
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte(""),
|
||||
},
|
||||
},
|
||||
expectResult: []string{"system:bootstrappers"},
|
||||
},
|
||||
{
|
||||
name: "invalid prefix",
|
||||
secret: &api.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test"},
|
||||
Data: map[string][]byte{
|
||||
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("foo"),
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
secret: &api.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test"},
|
||||
Data: map[string][]byte{
|
||||
bootstrapapi.BootstrapTokenExtraGroupsKey: []byte("system:bootstrappers:foo,system:bootstrappers:bar,system:bootstrappers:bar"),
|
||||
},
|
||||
},
|
||||
// expect the results in deduplicated, sorted order
|
||||
expectResult: []string{
|
||||
"system:bootstrappers",
|
||||
"system:bootstrappers:bar",
|
||||
"system:bootstrappers:foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
result, err := getGroups(test.secret)
|
||||
if test.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("test %q expected an error, but didn't get one (result: %#v)", test.name, result)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("test %q return an unexpected error: %v", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(result, test.expectResult) {
|
||||
t.Errorf("test %q expected %#v, got %#v", test.name, test.expectResult, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user