mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #112590 from liggitt/authorizer_config
improve integration test customization of authn/authz
This commit is contained in:
commit
a2dc82f0b8
@ -35,6 +35,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -54,11 +55,9 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||||
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||||
"k8s.io/apiserver/pkg/authentication/token/cache"
|
"k8s.io/apiserver/pkg/authentication/token/cache"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
unionauthz "k8s.io/apiserver/pkg/authorization/union"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest"
|
|
||||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
@ -69,7 +68,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/auth/authorizer/abac"
|
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
"k8s.io/kubernetes/pkg/controlplane"
|
||||||
"k8s.io/kubernetes/test/integration"
|
"k8s.io/kubernetes/test/integration"
|
||||||
"k8s.io/kubernetes/test/integration/authutil"
|
"k8s.io/kubernetes/test/integration/authutil"
|
||||||
@ -82,13 +80,6 @@ const (
|
|||||||
UnknownToken string = "qwerty" // Not present in token file.
|
UnknownToken string = "qwerty" // Not present in token file.
|
||||||
)
|
)
|
||||||
|
|
||||||
func getTestTokenAuth() authenticator.Request {
|
|
||||||
tokenAuthenticator := tokentest.New()
|
|
||||||
tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"}
|
|
||||||
tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"}
|
|
||||||
return group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated})
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTestWebhookTokenAuth(serverURL string, customDial utilnet.DialFunc) (authenticator.Request, error) {
|
func getTestWebhookTokenAuth(serverURL string, customDial utilnet.DialFunc) (authenticator.Request, error) {
|
||||||
kubecfgFile, err := os.CreateTemp("", "webhook-kubecfg")
|
kubecfgFile, err := os.CreateTemp("", "webhook-kubecfg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -464,9 +455,7 @@ func TestAuthModeAlwaysAllow(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -570,10 +559,8 @@ func TestAuthModeAlwaysDeny(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authorization.Modes = []string{"AlwaysDeny"}
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -609,17 +596,6 @@ func TestAuthModeAlwaysDeny(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject into control plane an authorizer that uses user info.
|
|
||||||
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
|
||||||
type allowAliceAuthorizer struct{}
|
|
||||||
|
|
||||||
func (allowAliceAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
|
||||||
return authorizer.DecisionAllow, "", nil
|
|
||||||
}
|
|
||||||
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to
|
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to
|
||||||
// the authentication system and authorized to do any actions.
|
// the authentication system and authorized to do any actions.
|
||||||
func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
|
func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
|
||||||
@ -627,10 +603,9 @@ func TestAliceNotForbiddenOrUnauthorized(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.PolicyFile = "testdata/allowalice.jsonl"
|
||||||
config.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -704,10 +679,9 @@ func TestBobIsForbidden(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.PolicyFile = "testdata/allowalice.jsonl"
|
||||||
config.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -754,10 +728,9 @@ func TestUnknownUserIsUnauthorized(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.PolicyFile = "testdata/allowalice.jsonl"
|
||||||
config.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -807,10 +780,13 @@ func (impersonateAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
|
|||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() != "impersonate" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() != "impersonate" {
|
||||||
return authorizer.DecisionAllow, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
// bob can impersonate anyone, but that it
|
// bob can impersonate anyone, but that's it
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() == "impersonate" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() == "impersonate" {
|
||||||
return authorizer.DecisionAllow, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() != "impersonate" {
|
||||||
|
return authorizer.DecisionDeny, "", nil
|
||||||
|
}
|
||||||
// service accounts can do everything
|
// service accounts can do everything
|
||||||
if a.GetUser() != nil && strings.HasPrefix(a.GetUser().GetName(), serviceaccount.ServiceAccountUsernamePrefix) {
|
if a.GetUser() != nil && strings.HasPrefix(a.GetUser().GetName(), serviceaccount.ServiceAccountUsernamePrefix) {
|
||||||
return authorizer.DecisionAllow, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
@ -824,10 +800,11 @@ func TestImpersonateIsForbidden(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
},
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
// Prepend an impersonation authorizer with specific opinions about alice and bob
|
||||||
config.GenericConfig.Authorization.Authorizer = impersonateAuthorizer{}
|
config.GenericConfig.Authorization.Authorizer = unionauthz.New(impersonateAuthorizer{}, config.GenericConfig.Authorization.Authorizer)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -860,7 +837,7 @@ func TestImpersonateIsForbidden(t *testing.T) {
|
|||||||
// Expect all of bob's actions to return Forbidden
|
// Expect all of bob's actions to return Forbidden
|
||||||
if resp.StatusCode != http.StatusForbidden {
|
if resp.StatusCode != http.StatusForbidden {
|
||||||
t.Logf("case %v", r)
|
t.Logf("case %v", r)
|
||||||
t.Errorf("Expected not status Forbidden, but got %s", resp.Status)
|
t.Errorf("Expected status Forbidden, but got %s", resp.Status)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -1101,23 +1078,13 @@ func csrPEM(t *testing.T) []byte {
|
|||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAuthorizerWithContents(t *testing.T, contents string) authorizer.Authorizer {
|
func newABACFileWithContents(t *testing.T, contents string) string {
|
||||||
f, err := os.CreateTemp("", "auth_test")
|
dir := t.TempDir()
|
||||||
if err != nil {
|
file := filepath.Join(dir, "auth_test")
|
||||||
t.Fatalf("unexpected error creating policyfile: %v", err)
|
if err := os.WriteFile(file, []byte(contents), 0700); err != nil {
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
defer os.Remove(f.Name())
|
|
||||||
|
|
||||||
if err := os.WriteFile(f.Name(), []byte(contents), 0700); err != nil {
|
|
||||||
t.Fatalf("unexpected error writing policyfile: %v", err)
|
t.Fatalf("unexpected error writing policyfile: %v", err)
|
||||||
}
|
}
|
||||||
|
return file
|
||||||
pl, err := abac.NewFromFile(f.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error creating authorizer from policyfile: %v", err)
|
|
||||||
}
|
|
||||||
return pl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type trackingAuthorizer struct {
|
type trackingAuthorizer struct {
|
||||||
@ -1137,10 +1104,10 @@ func TestAuthorizationAttributeDetermination(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
},
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
config.GenericConfig.Authorization.Authorizer = unionauthz.New(config.GenericConfig.Authorization.Authorizer, trackingAuthorizer)
|
||||||
config.GenericConfig.Authorization.Authorizer = trackingAuthorizer
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -1203,18 +1170,13 @@ func TestAuthorizationAttributeDetermination(t *testing.T) {
|
|||||||
// TestNamespaceAuthorization tests that authorization can be controlled
|
// TestNamespaceAuthorization tests that authorization can be controlled
|
||||||
// by namespace.
|
// by namespace.
|
||||||
func TestNamespaceAuthorization(t *testing.T) {
|
func TestNamespaceAuthorization(t *testing.T) {
|
||||||
// This file has alice and bob in it.
|
|
||||||
a := newAuthorizerWithContents(t, `{"namespace": "auth-namespace"}
|
|
||||||
`)
|
|
||||||
|
|
||||||
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.PolicyFile = newABACFileWithContents(t, `{"namespace": "auth-namespace"}`)
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authorization.Authorizer = a
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -1309,18 +1271,13 @@ func TestNamespaceAuthorization(t *testing.T) {
|
|||||||
// TestKindAuthorization tests that authorization can be controlled
|
// TestKindAuthorization tests that authorization can be controlled
|
||||||
// by namespace.
|
// by namespace.
|
||||||
func TestKindAuthorization(t *testing.T) {
|
func TestKindAuthorization(t *testing.T) {
|
||||||
// This file has alice and bob in it.
|
|
||||||
a := newAuthorizerWithContents(t, `{"resource": "services"}
|
|
||||||
`)
|
|
||||||
|
|
||||||
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.PolicyFile = newABACFileWithContents(t, `{"resource": "services"}`)
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authorization.Authorizer = a
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -1397,17 +1354,13 @@ func TestKindAuthorization(t *testing.T) {
|
|||||||
// TestReadOnlyAuthorization tests that authorization can be controlled
|
// TestReadOnlyAuthorization tests that authorization can be controlled
|
||||||
// by namespace.
|
// by namespace.
|
||||||
func TestReadOnlyAuthorization(t *testing.T) {
|
func TestReadOnlyAuthorization(t *testing.T) {
|
||||||
// This file has alice and bob in it.
|
|
||||||
a := newAuthorizerWithContents(t, `{"readonly": true}`)
|
|
||||||
|
|
||||||
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
},
|
opts.Authentication.TokenFile.TokenFile = "testdata/tokens.csv"
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
opts.Authorization.PolicyFile = newABACFileWithContents(t, `{"readonly": true}`)
|
||||||
config.GenericConfig.Authentication.Authenticator = getTestTokenAuth()
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
config.GenericConfig.Authorization.Authorizer = a
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -1484,12 +1437,13 @@ func testWebhookTokenAuthenticator(customDialer bool, t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
|
opts.Authorization.Modes = []string{"ABAC"}
|
||||||
|
opts.Authorization.PolicyFile = "testdata/allowalice.jsonl"
|
||||||
},
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authentication.Authenticator = group.NewAuthenticatedGroupAdder(authenticator)
|
config.GenericConfig.Authentication.Authenticator = group.NewAuthenticatedGroupAdder(authenticator)
|
||||||
// Disable checking API audiences that is set by testserver by default.
|
// Disable checking API audiences that is set by testserver by default.
|
||||||
config.GenericConfig.Authentication.APIAudiences = nil
|
config.GenericConfig.Authentication.APIAudiences = nil
|
||||||
config.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
|
@ -29,9 +29,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apiserver/pkg/authentication/group"
|
"k8s.io/apiserver/pkg/authentication/group"
|
||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
|
bootstrapapi "k8s.io/cluster-bootstrap/token/api"
|
||||||
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
"k8s.io/kubernetes/pkg/controlplane"
|
||||||
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
|
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
|
||||||
"k8s.io/kubernetes/test/integration"
|
"k8s.io/kubernetes/test/integration"
|
||||||
@ -122,9 +122,11 @@ func TestBootstrapTokenAuth(t *testing.T) {
|
|||||||
authenticator := group.NewAuthenticatedGroupAdder(bearertoken.New(bootstrap.NewTokenAuthenticator(bootstrapSecrets{test.secret})))
|
authenticator := group.NewAuthenticatedGroupAdder(bearertoken.New(bootstrap.NewTokenAuthenticator(bootstrapSecrets{test.secret})))
|
||||||
|
|
||||||
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authentication.Authenticator = authenticator
|
config.GenericConfig.Authentication.Authenticator = authenticator
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
|
@ -24,12 +24,10 @@ import (
|
|||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/controller-manager/pkg/clientbuilder"
|
"k8s.io/controller-manager/pkg/clientbuilder"
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
|
||||||
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
|
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
)
|
)
|
||||||
@ -67,9 +65,7 @@ func TestDynamicClientBuilder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
opts.Authentication.ServiceAccounts.Issuers = []string{iss}
|
opts.Authentication.ServiceAccounts.Issuers = []string{iss}
|
||||||
opts.Authentication.ServiceAccounts.KeyFiles = []string{tmpfile.Name()}
|
opts.Authentication.ServiceAccounts.KeyFiles = []string{tmpfile.Name()}
|
||||||
},
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
|
@ -35,9 +35,11 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
"k8s.io/apiserver/pkg/authentication/group"
|
"k8s.io/apiserver/pkg/authentication/group"
|
||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
||||||
|
unionauthn "k8s.io/apiserver/pkg/authentication/request/union"
|
||||||
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
|
"k8s.io/apiserver/pkg/authentication/token/tokenfile"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
unionauthz "k8s.io/apiserver/pkg/authorization/union"
|
||||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -552,10 +554,16 @@ func TestRBAC(t *testing.T) {
|
|||||||
// Also disable namespace lifecycle to workaroung the test limitation that first creates
|
// Also disable namespace lifecycle to workaroung the test limitation that first creates
|
||||||
// roles/rolebindings and only then creates corresponding namespaces.
|
// roles/rolebindings and only then creates corresponding namespaces.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount", "NamespaceLifecycle"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount", "NamespaceLifecycle"}
|
||||||
|
// Disable built-in authorizers
|
||||||
|
opts.Authorization.Modes = []string{"AlwaysDeny"}
|
||||||
},
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authentication.Authenticator = authenticator
|
// Append our custom test authenticator
|
||||||
config.GenericConfig.Authorization.Authorizer, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
config.GenericConfig.Authentication.Authenticator = unionauthn.New(config.GenericConfig.Authentication.Authenticator, authenticator)
|
||||||
|
// Append our custom test authorizer
|
||||||
|
var rbacAuthz authorizer.Authorizer
|
||||||
|
rbacAuthz, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
||||||
|
config.GenericConfig.Authorization.Authorizer = unionauthz.New(config.GenericConfig.Authorization.Authorizer, rbacAuthz)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -666,20 +674,9 @@ func TestRBAC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBootstrapping(t *testing.T) {
|
func TestBootstrapping(t *testing.T) {
|
||||||
superUser := "admin/system:masters"
|
|
||||||
|
|
||||||
var tearDownAuthorizerFn func()
|
|
||||||
defer func() {
|
|
||||||
if tearDownAuthorizerFn != nil {
|
|
||||||
tearDownAuthorizerFn()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
clientset, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
clientset, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
config.GenericConfig.Authentication.Authenticator = bearertoken.New(tokenfile.New(map[string]*user.DefaultInfo{
|
opts.Authorization.Modes = []string{"RBAC"}
|
||||||
superUser: {Name: "admin", Groups: []string{"system:masters"}},
|
|
||||||
}))
|
|
||||||
config.GenericConfig.Authorization.Authorizer, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -732,14 +729,6 @@ func TestDiscoveryUpgradeBootstrapping(t *testing.T) {
|
|||||||
tearDownFn()
|
tearDownFn()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var tearDownAuthorizerFn func()
|
|
||||||
defer func() {
|
|
||||||
if tearDownAuthorizerFn != nil {
|
|
||||||
tearDownAuthorizerFn()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
superUser := "admin/system:masters"
|
|
||||||
|
|
||||||
etcdConfig := framework.SharedEtcd()
|
etcdConfig := framework.SharedEtcd()
|
||||||
|
|
||||||
@ -747,12 +736,7 @@ func TestDiscoveryUpgradeBootstrapping(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Ensure we're using the same etcd across apiserver restarts.
|
// Ensure we're using the same etcd across apiserver restarts.
|
||||||
opts.Etcd.StorageConfig = *etcdConfig
|
opts.Etcd.StorageConfig = *etcdConfig
|
||||||
},
|
opts.Authorization.Modes = []string{"RBAC"}
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
|
||||||
config.GenericConfig.Authentication.Authenticator = bearertoken.New(tokenfile.New(map[string]*user.DefaultInfo{
|
|
||||||
superUser: {Name: "admin", Groups: []string{"system:masters"}},
|
|
||||||
}))
|
|
||||||
config.GenericConfig.Authorization.Authorizer, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -793,8 +777,6 @@ func TestDiscoveryUpgradeBootstrapping(t *testing.T) {
|
|||||||
// Stop the first API server.
|
// Stop the first API server.
|
||||||
tearDownFn()
|
tearDownFn()
|
||||||
tearDownFn = nil
|
tearDownFn = nil
|
||||||
tearDownAuthorizerFn()
|
|
||||||
tearDownAuthorizerFn = nil
|
|
||||||
|
|
||||||
// Check that upgraded API servers inherit `system:public-info-viewer` settings from
|
// Check that upgraded API servers inherit `system:public-info-viewer` settings from
|
||||||
// `system:discovery`, and respect auto-reconciliation annotations.
|
// `system:discovery`, and respect auto-reconciliation annotations.
|
||||||
@ -802,12 +784,7 @@ func TestDiscoveryUpgradeBootstrapping(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Ensure we're using the same etcd across apiserver restarts.
|
// Ensure we're using the same etcd across apiserver restarts.
|
||||||
opts.Etcd.StorageConfig = *etcdConfig
|
opts.Etcd.StorageConfig = *etcdConfig
|
||||||
},
|
opts.Authorization.Modes = []string{"RBAC"}
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
|
||||||
config.GenericConfig.Authentication.Authenticator = bearertoken.New(tokenfile.New(map[string]*user.DefaultInfo{
|
|
||||||
superUser: {Name: "admin", Groups: []string{"system:masters"}},
|
|
||||||
}))
|
|
||||||
config.GenericConfig.Authorization.Authorizer, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
@ -96,6 +95,10 @@ func TestGetsSelfAttributes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kubeClient, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
|
opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
|
||||||
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
// Unset BearerToken to disable BearerToken authenticator.
|
// Unset BearerToken to disable BearerToken authenticator.
|
||||||
config.GenericConfig.LoopbackClientConfig.BearerToken = ""
|
config.GenericConfig.LoopbackClientConfig.BearerToken = ""
|
||||||
@ -104,10 +107,6 @@ func TestGetsSelfAttributes(t *testing.T) {
|
|||||||
defer respMu.RUnlock()
|
defer respMu.RUnlock()
|
||||||
return &authenticator.Response{User: response}, true, nil
|
return &authenticator.Response{User: response}, true, nil
|
||||||
})
|
})
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
|
||||||
},
|
|
||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
|
||||||
opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -156,6 +155,10 @@ func TestGetsSelfAttributesError(t *testing.T) {
|
|||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.APISelfSubjectReview, true)()
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.APISelfSubjectReview, true)()
|
||||||
|
|
||||||
kubeClient, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
kubeClient, _, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
|
opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
|
||||||
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
// Unset BearerToken to disable BearerToken authenticator.
|
// Unset BearerToken to disable BearerToken authenticator.
|
||||||
config.GenericConfig.LoopbackClientConfig.BearerToken = ""
|
config.GenericConfig.LoopbackClientConfig.BearerToken = ""
|
||||||
@ -170,10 +173,6 @@ func TestGetsSelfAttributesError(t *testing.T) {
|
|||||||
|
|
||||||
return nil, false, fmt.Errorf("test error")
|
return nil, false, fmt.Errorf("test error")
|
||||||
})
|
})
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
|
||||||
},
|
|
||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
|
||||||
opts.APIEnablement.RuntimeConfig.Set("authentication.k8s.io/v1alpha1=true")
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
|
@ -19,12 +19,10 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -42,18 +40,12 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
|
||||||
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
v1listers "k8s.io/client-go/listers/core/v1"
|
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
"k8s.io/client-go/util/keyutil"
|
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
"k8s.io/kubernetes/pkg/apis/core"
|
"k8s.io/kubernetes/pkg/apis/core"
|
||||||
serviceaccountgetter "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
"k8s.io/kubernetes/pkg/controlplane"
|
||||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
@ -71,15 +63,6 @@ AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServiceAccountTokenCreate(t *testing.T) {
|
func TestServiceAccountTokenCreate(t *testing.T) {
|
||||||
|
|
||||||
// Build client config, clientset, and informers
|
|
||||||
sk, err := keyutil.ParsePrivateKeyPEM([]byte(ecdsaPrivateKey))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pk := sk.(*ecdsa.PrivateKey).PublicKey
|
|
||||||
|
|
||||||
const iss = "https://foo.bar.example.com"
|
const iss = "https://foo.bar.example.com"
|
||||||
aud := authenticator.Audiences{"api"}
|
aud := authenticator.Audiences{"api"}
|
||||||
|
|
||||||
@ -89,12 +72,7 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
|||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gcs := &clientset.Clientset{}
|
var tokenGenerator serviceaccount.TokenGenerator
|
||||||
|
|
||||||
tokenGenerator, err := serviceaccount.JWTTokenGenerator(iss, sk)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
var serverAddress string
|
var serverAddress string
|
||||||
@ -102,45 +80,21 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
|||||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount"}
|
||||||
|
opts.Authorization.Modes = []string{"AlwaysAllow"}
|
||||||
|
// Disable token cache so we can check reaction to service account deletion quickly
|
||||||
|
opts.Authentication.TokenSuccessCacheTTL = 0
|
||||||
|
opts.Authentication.TokenFailureCacheTTL = 0
|
||||||
|
// Pin to fixed URLs for easier testing
|
||||||
|
opts.Authentication.ServiceAccounts.JWKSURI = "https:///openid/v1/jwks"
|
||||||
|
opts.Authentication.ServiceAccounts.Issuers = []string{iss}
|
||||||
|
opts.Authentication.APIAudiences = aud
|
||||||
},
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
|
// extract token generator
|
||||||
config.GenericConfig.Authentication.APIAudiences = aud
|
tokenGenerator = config.ExtraConfig.ServiceAccountIssuer
|
||||||
config.GenericConfig.Authentication.Authenticator = bearertoken.New(
|
|
||||||
serviceaccount.JWTTokenAuthenticator(
|
|
||||||
[]string{iss},
|
|
||||||
[]interface{}{&pk},
|
|
||||||
aud,
|
|
||||||
serviceaccount.NewValidator(serviceaccountgetter.NewGetterFromClient(
|
|
||||||
gcs,
|
|
||||||
v1listers.NewSecretLister(newIndexer(func(namespace, name string) (interface{}, error) {
|
|
||||||
return gcs.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
||||||
})),
|
|
||||||
v1listers.NewServiceAccountLister(newIndexer(func(namespace, name string) (interface{}, error) {
|
|
||||||
return gcs.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
||||||
})),
|
|
||||||
v1listers.NewPodLister(newIndexer(func(namespace, name string) (interface{}, error) {
|
|
||||||
return gcs.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
||||||
})),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
config.ExtraConfig.ServiceAccountIssuer = tokenGenerator
|
|
||||||
config.ExtraConfig.ServiceAccountMaxExpiration = maxExpirationDuration
|
config.ExtraConfig.ServiceAccountMaxExpiration = maxExpirationDuration
|
||||||
config.ExtraConfig.ExtendExpiration = true
|
config.ExtraConfig.ExtendExpiration = true
|
||||||
|
|
||||||
config.ExtraConfig.ServiceAccountIssuerURL = iss
|
|
||||||
config.ExtraConfig.ServiceAccountJWKSURI = ""
|
|
||||||
config.ExtraConfig.ServiceAccountPublicKeys = []interface{}{&pk}
|
|
||||||
|
|
||||||
// Compute the serverAddress.
|
|
||||||
serverAddress = config.GenericConfig.ExternalAddress
|
|
||||||
_, port, err := config.GenericConfig.SecureServing.HostPort()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Couldn't get server port: %v", err)
|
|
||||||
}
|
|
||||||
serverAddress = net.JoinHostPort(serverAddress, strconv.Itoa(port))
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
defer tearDownFn()
|
defer tearDownFn()
|
||||||
@ -156,7 +110,6 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
*gcs = *cs
|
|
||||||
|
|
||||||
kubeConfig.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
kubeConfig.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||||
rc, err := rest.UnversionedRESTClientFor(kubeConfig)
|
rc, err := rest.UnversionedRESTClientFor(kubeConfig)
|
||||||
@ -917,6 +870,8 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
|||||||
|
|
||||||
func doTokenReview(t *testing.T, cs clientset.Interface, treq *authenticationv1.TokenRequest, expectErr bool) authenticationv1.UserInfo {
|
func doTokenReview(t *testing.T, cs clientset.Interface, treq *authenticationv1.TokenRequest, expectErr bool) authenticationv1.UserInfo {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
trev, err := cs.AuthenticationV1().TokenReviews().Create(context.TODO(), &authenticationv1.TokenReview{
|
trev, err := cs.AuthenticationV1().TokenReviews().Create(context.TODO(), &authenticationv1.TokenReview{
|
||||||
Spec: authenticationv1.TokenReviewSpec{
|
Spec: authenticationv1.TokenReviewSpec{
|
||||||
Token: treq.Status.Token,
|
Token: treq.Status.Token,
|
||||||
@ -930,6 +885,14 @@ func doTokenReview(t *testing.T, cs clientset.Interface, treq *authenticationv1.
|
|||||||
t.Fatalf("expected no error but got: %v", trev.Status.Error)
|
t.Fatalf("expected no error but got: %v", trev.Status.Error)
|
||||||
}
|
}
|
||||||
if (trev.Status.Error == "") && expectErr {
|
if (trev.Status.Error == "") && expectErr {
|
||||||
|
// if we expected an error and didn't get one, retry
|
||||||
|
// to let changes that invalidate the token percolate through informers
|
||||||
|
if tries < 10 {
|
||||||
|
tries++
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
t.Logf("expected error but got: %+v, retrying", trev.Status)
|
||||||
|
continue
|
||||||
|
}
|
||||||
t.Fatalf("expected error but got: %+v", trev.Status)
|
t.Fatalf("expected error but got: %+v", trev.Status)
|
||||||
}
|
}
|
||||||
if !trev.Status.Authenticated && !expectErr {
|
if !trev.Status.Authenticated && !expectErr {
|
||||||
@ -937,6 +900,7 @@ func doTokenReview(t *testing.T, cs clientset.Interface, treq *authenticationv1.
|
|||||||
}
|
}
|
||||||
return trev.Status.User
|
return trev.Status.User
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkPayload(t *testing.T, tok string, want string, parts ...string) {
|
func checkPayload(t *testing.T, tok string, want string, parts ...string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -1043,26 +1007,6 @@ func createDeleteSecret(t *testing.T, cs clientset.Interface, sec *v1.Secret) (*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIndexer(get func(namespace, name string) (interface{}, error)) cache.Indexer {
|
|
||||||
return &fakeIndexer{get: get}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeIndexer struct {
|
|
||||||
cache.Indexer
|
|
||||||
get func(namespace, name string) (interface{}, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fakeIndexer) GetByKey(key string) (interface{}, bool, error) {
|
|
||||||
parts := strings.SplitN(key, "/", 2)
|
|
||||||
namespace := parts[0]
|
|
||||||
name := ""
|
|
||||||
if len(parts) == 2 {
|
|
||||||
name = parts[1]
|
|
||||||
}
|
|
||||||
obj, err := f.get(namespace, name)
|
|
||||||
return obj, err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type recordingWarningHandler struct {
|
type recordingWarningHandler struct {
|
||||||
warnings []string
|
warnings []string
|
||||||
|
|
||||||
|
1
test/integration/auth/testdata/allowalice.jsonl
vendored
Normal file
1
test/integration/auth/testdata/allowalice.jsonl
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"alice", "namespace": "*", "resource": "*", "apiGroup": "*", "nonResourcePath": "*"}}
|
2
test/integration/auth/testdata/tokens.csv
vendored
Normal file
2
test/integration/auth/testdata/tokens.csv
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
abc123,alice,1
|
||||||
|
xyz987,bob,2
|
|
@ -39,20 +39,11 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
authauthenticator "k8s.io/apiserver/pkg/authentication/authenticator"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/group"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
|
||||||
authenticatorunion "k8s.io/apiserver/pkg/authentication/request/union"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
|
||||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
clienttypedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
clienttypedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
|
||||||
"k8s.io/kubernetes/test/integration"
|
"k8s.io/kubernetes/test/integration"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
)
|
)
|
||||||
@ -63,15 +54,6 @@ const (
|
|||||||
BobToken string = "xyz987" // username: bob. Present in token file.
|
BobToken string = "xyz987" // username: bob. Present in token file.
|
||||||
)
|
)
|
||||||
|
|
||||||
type allowAliceAuthorizer struct{}
|
|
||||||
|
|
||||||
func (allowAliceAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
|
||||||
return authorizer.DecisionAllow, "", nil
|
|
||||||
}
|
|
||||||
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func testPrefix(t *testing.T, prefix string) {
|
func testPrefix(t *testing.T, prefix string) {
|
||||||
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
|
server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
|
||||||
defer server.TearDownFn()
|
defer server.TearDownFn()
|
||||||
@ -163,31 +145,18 @@ func TestEmptyList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initStatusForbiddenControlPlaneConfig(config *controlplane.Config) {
|
func initStatusForbiddenControlPlaneConfig(options *options.ServerRunOptions) {
|
||||||
config.GenericConfig.Authentication.Authenticator = authenticatorunion.New(
|
options.Authorization.Modes = []string{"AlwaysDeny"}
|
||||||
authauthenticator.RequestFunc(func(req *http.Request) (*authauthenticator.Response, bool, error) {
|
|
||||||
return &authauthenticator.Response{
|
|
||||||
User: &user.DefaultInfo{
|
|
||||||
Name: "unprivileged",
|
|
||||||
Groups: []string{user.AllAuthenticated},
|
|
||||||
},
|
|
||||||
}, true, nil
|
|
||||||
}))
|
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysDenyAuthorizer()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initUnauthorizedControlPlaneConfig(config *controlplane.Config) {
|
func initUnauthorizedControlPlaneConfig(options *options.ServerRunOptions) {
|
||||||
tokenAuthenticator := tokentest.New()
|
options.Authentication.Anonymous.Allow = false
|
||||||
tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"}
|
|
||||||
tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"}
|
|
||||||
config.GenericConfig.Authentication.Authenticator = group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated})
|
|
||||||
config.GenericConfig.Authorization.Authorizer = allowAliceAuthorizer{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStatus(t *testing.T) {
|
func TestStatus(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
modifyConfig func(*controlplane.Config)
|
modifyOptions func(*options.ServerRunOptions)
|
||||||
statusCode int
|
statusCode int
|
||||||
reqPath string
|
reqPath string
|
||||||
reason string
|
reason string
|
||||||
@ -195,7 +164,6 @@ func TestStatus(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "404",
|
name: "404",
|
||||||
modifyConfig: nil,
|
|
||||||
statusCode: http.StatusNotFound,
|
statusCode: http.StatusNotFound,
|
||||||
reqPath: "/apis/batch/v1/namespaces/default/jobs/foo",
|
reqPath: "/apis/batch/v1/namespaces/default/jobs/foo",
|
||||||
reason: "NotFound",
|
reason: "NotFound",
|
||||||
@ -203,15 +171,15 @@ func TestStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "403",
|
name: "403",
|
||||||
modifyConfig: initStatusForbiddenControlPlaneConfig,
|
modifyOptions: initStatusForbiddenControlPlaneConfig,
|
||||||
statusCode: http.StatusForbidden,
|
statusCode: http.StatusForbidden,
|
||||||
reqPath: "/apis",
|
reqPath: "/apis",
|
||||||
reason: "Forbidden",
|
reason: "Forbidden",
|
||||||
message: `forbidden: User "unprivileged" cannot get path "/apis": Everything is forbidden.`,
|
message: `forbidden: User "system:anonymous" cannot get path "/apis": Everything is forbidden.`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "401",
|
name: "401",
|
||||||
modifyConfig: initUnauthorizedControlPlaneConfig,
|
modifyOptions: initUnauthorizedControlPlaneConfig,
|
||||||
statusCode: http.StatusUnauthorized,
|
statusCode: http.StatusUnauthorized,
|
||||||
reqPath: "/apis",
|
reqPath: "/apis",
|
||||||
reason: "Unauthorized",
|
reason: "Unauthorized",
|
||||||
@ -222,9 +190,9 @@ func TestStatus(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
_, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
_, kubeConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerRunOptions: func(options *options.ServerRunOptions) {
|
||||||
if tc.modifyConfig != nil {
|
if tc.modifyOptions != nil {
|
||||||
tc.modifyConfig(config)
|
tc.modifyOptions(options)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -232,7 +200,7 @@ func TestStatus(t *testing.T) {
|
|||||||
|
|
||||||
// When modifying authenticator and authorizer, don't use
|
// When modifying authenticator and authorizer, don't use
|
||||||
// bearer token than will be always authorized.
|
// bearer token than will be always authorized.
|
||||||
if tc.modifyConfig != nil {
|
if tc.modifyOptions != nil {
|
||||||
kubeConfig.BearerToken = ""
|
kubeConfig.BearerToken = ""
|
||||||
}
|
}
|
||||||
transport, err := restclient.TransportFor(kubeConfig)
|
transport, err := restclient.TransportFor(kubeConfig)
|
||||||
|
@ -22,8 +22,6 @@ package serviceaccount
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -33,18 +31,16 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/group"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
|
|
||||||
"k8s.io/apiserver/pkg/authentication/request/union"
|
|
||||||
serviceaccountapiserver "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
serviceaccountapiserver "k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
unionauthz "k8s.io/apiserver/pkg/authorization/union"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
clientinformers "k8s.io/client-go/informers"
|
clientinformers "k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/util/keyutil"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
|
||||||
"k8s.io/kubernetes/pkg/controlplane"
|
"k8s.io/kubernetes/pkg/controlplane"
|
||||||
@ -55,9 +51,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rootUserName = "root"
|
|
||||||
rootToken = "root-user-token" // Fake value for testing.
|
|
||||||
|
|
||||||
readOnlyServiceAccountName = "ro"
|
readOnlyServiceAccountName = "ro"
|
||||||
readWriteServiceAccountName = "rw"
|
readWriteServiceAccountName = "rw"
|
||||||
)
|
)
|
||||||
@ -319,50 +312,19 @@ func TestServiceAccountTokenAuthentication(t *testing.T) {
|
|||||||
|
|
||||||
// startServiceAccountTestServerAndWaitForCaches returns a started server
|
// startServiceAccountTestServerAndWaitForCaches returns a started server
|
||||||
// It is the responsibility of the caller to ensure the returned stopFunc is called
|
// It is the responsibility of the caller to ensure the returned stopFunc is called
|
||||||
func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Clientset, *restclient.Config, func(), error) {
|
func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (clientset.Interface, *restclient.Config, func(), error) {
|
||||||
rootTokenAuth := authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) {
|
var serviceAccountKey interface{}
|
||||||
if token == rootToken {
|
|
||||||
return &authenticator.Response{User: &user.DefaultInfo{Name: rootUserName}}, true, nil
|
|
||||||
}
|
|
||||||
return nil, false, nil
|
|
||||||
})
|
|
||||||
serviceAccountKey, _ := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
|
|
||||||
var informers clientinformers.SharedInformerFactory
|
|
||||||
var externalInformers clientinformers.SharedInformerFactory
|
|
||||||
var rootClientset *clientset.Clientset
|
|
||||||
|
|
||||||
// Set up a API server
|
// Set up a API server
|
||||||
_, clientConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
rootClientset, clientConfig, tearDownFn := framework.StartTestServer(t, framework.TestServerSetup{
|
||||||
|
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||||
|
var err error
|
||||||
|
serviceAccountKey, err = keyutil.PrivateKeyFromFile(opts.ServiceAccountSigningKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
ModifyServerConfig: func(config *controlplane.Config) {
|
ModifyServerConfig: func(config *controlplane.Config) {
|
||||||
rootConfig := restclient.CopyConfig(config.GenericConfig.LoopbackClientConfig)
|
|
||||||
rootConfig.BearerToken = rootToken
|
|
||||||
rootClientset = clientset.NewForConfigOrDie(rootConfig)
|
|
||||||
externalRootClientset := clientset.NewForConfigOrDie(rootConfig)
|
|
||||||
|
|
||||||
externalInformers = clientinformers.NewSharedInformerFactory(externalRootClientset, controller.NoResyncPeriodFunc())
|
|
||||||
informers = clientinformers.NewSharedInformerFactory(rootClientset, controller.NoResyncPeriodFunc())
|
|
||||||
|
|
||||||
// Set up two authenticators:
|
|
||||||
// 1. A token authenticator that maps the rootToken to the "root" user
|
|
||||||
// 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens
|
|
||||||
serviceAccountTokenGetter := serviceaccountcontroller.NewGetterFromClient(
|
|
||||||
rootClientset,
|
|
||||||
externalInformers.Core().V1().Secrets().Lister(),
|
|
||||||
externalInformers.Core().V1().ServiceAccounts().Lister(),
|
|
||||||
externalInformers.Core().V1().Pods().Lister(),
|
|
||||||
)
|
|
||||||
serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator(
|
|
||||||
[]string{serviceaccount.LegacyIssuer},
|
|
||||||
[]interface{}{&serviceAccountKey.PublicKey},
|
|
||||||
nil,
|
|
||||||
serviceaccount.NewLegacyValidator(true, serviceAccountTokenGetter),
|
|
||||||
)
|
|
||||||
authenticator := group.NewAuthenticatedGroupAdder(union.New(
|
|
||||||
bearertoken.New(rootTokenAuth),
|
|
||||||
bearertoken.New(serviceAccountTokenAuth),
|
|
||||||
))
|
|
||||||
|
|
||||||
// Set up a stub authorizer:
|
// Set up a stub authorizer:
|
||||||
// 1. The "root" user is allowed to do anything
|
// 1. The "root" user is allowed to do anything
|
||||||
// 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace
|
// 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace
|
||||||
@ -374,12 +336,6 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Cli
|
|||||||
}
|
}
|
||||||
ns := attrs.GetNamespace()
|
ns := attrs.GetNamespace()
|
||||||
|
|
||||||
// If the user is "root"...
|
|
||||||
if username == rootUserName {
|
|
||||||
// allow them to do anything
|
|
||||||
return authorizer.DecisionAllow, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user is a service account...
|
// If the user is a service account...
|
||||||
if serviceAccountNamespace, serviceAccountName, err := serviceaccountapiserver.SplitUsername(username); err == nil {
|
if serviceAccountNamespace, serviceAccountName, err := serviceaccountapiserver.SplitUsername(username); err == nil {
|
||||||
// Limit them to their own namespace
|
// Limit them to their own namespace
|
||||||
@ -397,16 +353,7 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Cli
|
|||||||
|
|
||||||
return authorizer.DecisionNoOpinion, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil
|
return authorizer.DecisionNoOpinion, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil
|
||||||
})
|
})
|
||||||
|
config.GenericConfig.Authorization.Authorizer = unionauthz.New(config.GenericConfig.Authorization.Authorizer, authorizer)
|
||||||
// Set up admission plugin to auto-assign serviceaccounts to pods
|
|
||||||
serviceAccountAdmission := serviceaccountadmission.NewServiceAccount()
|
|
||||||
serviceAccountAdmission.SetExternalKubeClientSet(externalRootClientset)
|
|
||||||
serviceAccountAdmission.SetExternalKubeInformerFactory(externalInformers)
|
|
||||||
|
|
||||||
config.GenericConfig.EnableIndex = true
|
|
||||||
config.GenericConfig.Authentication.Authenticator = authenticator
|
|
||||||
config.GenericConfig.Authorization.Authorizer = authorizer
|
|
||||||
config.GenericConfig.AdmissionControl = serviceAccountAdmission
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -416,6 +363,8 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Cli
|
|||||||
tearDownFn()
|
tearDownFn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
informers := clientinformers.NewSharedInformerFactory(rootClientset, controller.NoResyncPeriodFunc())
|
||||||
|
|
||||||
// Start the service account and service account token controllers
|
// Start the service account and service account token controllers
|
||||||
tokenGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, serviceAccountKey)
|
tokenGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, serviceAccountKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -445,7 +394,6 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Cli
|
|||||||
return rootClientset, clientConfig, stop, err
|
return rootClientset, clientConfig, stop, err
|
||||||
}
|
}
|
||||||
informers.Start(ctx.Done())
|
informers.Start(ctx.Done())
|
||||||
externalInformers.Start(ctx.Done())
|
|
||||||
go serviceAccountController.Run(ctx, 5)
|
go serviceAccountController.Run(ctx, 5)
|
||||||
|
|
||||||
// since this method starts the controllers in a separate goroutine
|
// since this method starts the controllers in a separate goroutine
|
||||||
@ -453,12 +401,11 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (*clientset.Cli
|
|||||||
// the tests can tell it is safe to call the server and requests won't be rejected
|
// the tests can tell it is safe to call the server and requests won't be rejected
|
||||||
// thus we wait until caches have synced
|
// thus we wait until caches have synced
|
||||||
informers.WaitForCacheSync(ctx.Done())
|
informers.WaitForCacheSync(ctx.Done())
|
||||||
externalInformers.WaitForCacheSync(ctx.Done())
|
|
||||||
|
|
||||||
return rootClientset, clientConfig, stop, nil
|
return rootClientset, clientConfig, stop, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServiceAccount(c *clientset.Clientset, ns string, name string, shouldWait bool) (*v1.ServiceAccount, error) {
|
func getServiceAccount(c clientset.Interface, ns string, name string, shouldWait bool) (*v1.ServiceAccount, error) {
|
||||||
if !shouldWait {
|
if !shouldWait {
|
||||||
return c.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{})
|
return c.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
@ -478,7 +425,7 @@ func getServiceAccount(c *clientset.Clientset, ns string, name string, shouldWai
|
|||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createServiceAccountToken(c *clientset.Clientset, sa *v1.ServiceAccount, ns string, name string) (*v1.Secret, error) {
|
func createServiceAccountToken(c clientset.Interface, sa *v1.ServiceAccount, ns string, name string) (*v1.Secret, error) {
|
||||||
secret := &v1.Secret{
|
secret := &v1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -508,7 +455,7 @@ func createServiceAccountToken(c *clientset.Clientset, sa *v1.ServiceAccount, ns
|
|||||||
return secret, nil
|
return secret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReferencedServiceAccountToken(c *clientset.Clientset, ns string, name string, shouldWait bool) (string, string, error) {
|
func getReferencedServiceAccountToken(c clientset.Interface, ns string, name string, shouldWait bool) (string, string, error) {
|
||||||
tokenName := ""
|
tokenName := ""
|
||||||
token := ""
|
token := ""
|
||||||
|
|
||||||
@ -564,7 +511,7 @@ func getReferencedServiceAccountToken(c *clientset.Clientset, ns string, name st
|
|||||||
|
|
||||||
type testOperation func() error
|
type testOperation func() error
|
||||||
|
|
||||||
func doServiceAccountAPIRequests(t *testing.T, c *clientset.Clientset, ns string, authenticated bool, canRead bool, canWrite bool) {
|
func doServiceAccountAPIRequests(t *testing.T, c clientset.Interface, ns string, authenticated bool, canRead bool, canWrite bool) {
|
||||||
testSecret := &v1.Secret{
|
testSecret := &v1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "testSecret"},
|
ObjectMeta: metav1.ObjectMeta{Name: "testSecret"},
|
||||||
Data: map[string][]byte{"test": []byte("data")},
|
Data: map[string][]byte{"test": []byte("data")},
|
||||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1625,7 +1625,6 @@ k8s.io/apiserver/plugin/pkg/audit/log
|
|||||||
k8s.io/apiserver/plugin/pkg/audit/truncate
|
k8s.io/apiserver/plugin/pkg/audit/truncate
|
||||||
k8s.io/apiserver/plugin/pkg/audit/webhook
|
k8s.io/apiserver/plugin/pkg/audit/webhook
|
||||||
k8s.io/apiserver/plugin/pkg/authenticator/token/oidc
|
k8s.io/apiserver/plugin/pkg/authenticator/token/oidc
|
||||||
k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest
|
|
||||||
k8s.io/apiserver/plugin/pkg/authenticator/token/webhook
|
k8s.io/apiserver/plugin/pkg/authenticator/token/webhook
|
||||||
k8s.io/apiserver/plugin/pkg/authorizer/webhook
|
k8s.io/apiserver/plugin/pkg/authorizer/webhook
|
||||||
# k8s.io/cli-runtime v0.0.0 => ./staging/src/k8s.io/cli-runtime
|
# k8s.io/cli-runtime v0.0.0 => ./staging/src/k8s.io/cli-runtime
|
||||||
|
Loading…
Reference in New Issue
Block a user