Merge pull request #125836 from mjudeikis/mjudeikis/auth.token.getter

Extend service accounts with optional tokenGetter provider
This commit is contained in:
Kubernetes Prow Robot 2024-07-09 00:30:34 -07:00 committed by GitHub
commit 51bf5df54a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 8 deletions

View File

@ -132,6 +132,9 @@ type ServiceAccountAuthenticationOptions struct {
JWKSURI string
MaxExpiration time.Duration
ExtendExpiration bool
// OptionalTokenGetter is a function that returns a service account token getter.
// If not set, the default token getter will be used.
OptionalTokenGetter func(factory informers.SharedInformerFactory) serviceaccount.ServiceAccountTokenGetter
}
// TokenFileAuthenticationOptions contains token file authentication options for API Server
@ -207,7 +210,20 @@ func (o *BuiltInAuthenticationOptions) WithRequestHeader() *BuiltInAuthenticatio
// WithServiceAccounts set default value for service account authentication
func (o *BuiltInAuthenticationOptions) WithServiceAccounts() *BuiltInAuthenticationOptions {
o.ServiceAccounts = &ServiceAccountAuthenticationOptions{Lookup: true, ExtendExpiration: true}
if o.ServiceAccounts == nil {
o.ServiceAccounts = &ServiceAccountAuthenticationOptions{}
}
o.ServiceAccounts.Lookup = true
o.ServiceAccounts.ExtendExpiration = true
return o
}
// WithTokenGetterFunction set optional service account token getter function
func (o *BuiltInAuthenticationOptions) WithTokenGetterFunction(f func(factory informers.SharedInformerFactory) serviceaccount.ServiceAccountTokenGetter) *BuiltInAuthenticationOptions {
if o.ServiceAccounts == nil {
o.ServiceAccounts = &ServiceAccountAuthenticationOptions{}
}
o.ServiceAccounts.OptionalTokenGetter = f
return o
}
@ -673,13 +689,19 @@ func (o *BuiltInAuthenticationOptions) ApplyTo(
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceAccountTokenNodeBindingValidation) {
nodeLister = versionedInformer.Core().V1().Nodes().Lister()
}
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
extclient,
versionedInformer.Core().V1().Secrets().Lister(),
versionedInformer.Core().V1().ServiceAccounts().Lister(),
versionedInformer.Core().V1().Pods().Lister(),
nodeLister,
)
// If the optional token getter function is set, use it. Otherwise, use the default token getter.
if o.ServiceAccounts != nil && o.ServiceAccounts.OptionalTokenGetter != nil {
authenticatorConfig.ServiceAccountTokenGetter = o.ServiceAccounts.OptionalTokenGetter(versionedInformer)
} else {
authenticatorConfig.ServiceAccountTokenGetter = serviceaccountcontroller.NewGetterFromClient(
extclient,
versionedInformer.Core().V1().Secrets().Lister(),
versionedInformer.Core().V1().ServiceAccounts().Lister(),
versionedInformer.Core().V1().Pods().Lister(),
nodeLister,
)
}
authenticatorConfig.SecretsWriter = extclient.CoreV1()
if authenticatorConfig.BootstrapToken {

View File

@ -17,6 +17,7 @@ limitations under the License.
package options
import (
"context"
"os"
"reflect"
"strings"
@ -34,12 +35,17 @@ import (
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
"k8s.io/apiserver/pkg/authentication/request/headerrequest"
"k8s.io/apiserver/pkg/features"
genericapiserver "k8s.io/apiserver/pkg/server"
apiserveroptions "k8s.io/apiserver/pkg/server/options"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/component-base/featuregate"
featuregatetesting "k8s.io/component-base/featuregate/testing"
openapicommon "k8s.io/kube-openapi/pkg/common"
kubefeatures "k8s.io/kubernetes/pkg/features"
kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
"k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/utils/pointer"
)
@ -478,6 +484,39 @@ func TestBuiltInAuthenticationOptionsAddFlags(t *testing.T) {
}
}
func TestWithTokenGetterFunction(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, kubefeatures.ServiceAccountTokenNodeBindingValidation, false)
fakeClientset := fake.NewSimpleClientset()
versionedInformer := informers.NewSharedInformerFactory(fakeClientset, 0)
{
var called bool
f := func(factory informers.SharedInformerFactory) serviceaccount.ServiceAccountTokenGetter {
called = true
return nil
}
opts := NewBuiltInAuthenticationOptions().WithTokenGetterFunction(f)
err := opts.ApplyTo(context.Background(), &genericapiserver.AuthenticationInfo{}, nil, nil, &openapicommon.Config{}, nil, fakeClientset, versionedInformer, "")
if err != nil {
t.Fatal(err)
}
if opts.ServiceAccounts.OptionalTokenGetter == nil {
t.Fatal("expected token getter function to be set")
}
if !called {
t.Fatal("expected token getter function to be called")
}
}
{
opts := NewBuiltInAuthenticationOptions().WithServiceAccounts()
err := opts.ApplyTo(context.Background(), &genericapiserver.AuthenticationInfo{}, nil, nil, &openapicommon.Config{}, nil, fakeClientset, versionedInformer, "")
if err != nil {
t.Fatal(err)
}
}
}
func TestToAuthenticationConfig_Anonymous(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)
testCases := []struct {