impersonator_test.go: Test failed and anonymous auth

This commit is contained in:
Ryan Richard 2021-03-11 17:11:38 -08:00
parent 1d68841c78
commit 6ddf4c04e6

View File

@ -50,6 +50,13 @@ func TestImpersonator(t *testing.T) {
err = certKeyContent.SetCertKeyContent(cert, key) err = certKeyContent.SetCertKeyContent(cert, key)
require.NoError(t, err) require.NoError(t, err)
unrelatedCA, err := certauthority.New(pkix.Name{CommonName: "ca"}, time.Hour)
require.NoError(t, err)
badClientCertPEM, badClientKeyPEM, err := unrelatedCA.IssuePEM(
pkix.Name{CommonName: "test-user", Organization: []string{"test-group1"}}, nil, nil, time.Hour,
)
require.NoError(t, err)
// Punch out just enough stuff to make New actually run without error. // Punch out just enough stuff to make New actually run without error.
recOpts := func(options *genericoptions.RecommendedOptions) { recOpts := func(options *genericoptions.RecommendedOptions) {
options.Authentication.RemoteKubeConfigFileOptional = true options.Authentication.RemoteKubeConfigFileOptional = true
@ -63,9 +70,12 @@ func TestImpersonator(t *testing.T) {
name string name string
clientUsername string clientUsername string
clientGroups []string clientGroups []string
clientCertPEM string
clientKeyPEM string
clientImpersonateUser rest.ImpersonationConfig clientImpersonateUser rest.ImpersonationConfig
kubeAPIServerClientBearerTokenFile string kubeAPIServerClientBearerTokenFile string
kubeAPIServerStatusCode int kubeAPIServerStatusCode int
wantKubeAPIServerRequestHeaders http.Header
wantError string wantError string
wantConstructionError string wantConstructionError string
}{ }{
@ -74,10 +84,15 @@ func TestImpersonator(t *testing.T) {
clientUsername: "test-username", clientUsername: "test-username",
clientGroups: []string{"test-group1", "test-group2"}, clientGroups: []string{"test-group1", "test-group2"},
kubeAPIServerClientBearerTokenFile: "required-to-be-set", kubeAPIServerClientBearerTokenFile: "required-to-be-set",
}, wantKubeAPIServerRequestHeaders: http.Header{
{ "Impersonate-User": {"test-username"},
name: "no bearer token file in Kube API server client config", "Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
wantConstructionError: "invalid impersonator loopback rest config has wrong bearer token semantics", "Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
},
}, },
{ {
name: "user is authenticated but the kube API request returns an error", name: "user is authenticated but the kube API request returns an error",
@ -86,6 +101,37 @@ func TestImpersonator(t *testing.T) {
clientGroups: []string{"test-group1", "test-group2"}, clientGroups: []string{"test-group1", "test-group2"},
kubeAPIServerClientBearerTokenFile: "required-to-be-set", kubeAPIServerClientBearerTokenFile: "required-to-be-set",
wantError: `the server could not find the requested resource (get namespaces)`, wantError: `the server could not find the requested resource (get namespaces)`,
wantKubeAPIServerRequestHeaders: http.Header{
"Impersonate-User": {"test-username"},
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
},
},
{
name: "when there is no client cert on request, it is an anonymous request",
clientCertPEM: "present so we will use the empty keyPEM",
clientKeyPEM: "",
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
wantKubeAPIServerRequestHeaders: http.Header{
"Impersonate-User": {"system:anonymous"},
"Impersonate-Group": {"system:unauthenticated"},
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
},
},
{
name: "failed client cert authentication",
clientCertPEM: string(badClientCertPEM),
clientKeyPEM: string(badClientKeyPEM),
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
wantError: "Unauthorized",
}, },
{ {
name: "double impersonation is not allowed by regular users", name: "double impersonation is not allowed by regular users",
@ -105,6 +151,10 @@ func TestImpersonator(t *testing.T) {
wantError: `users "some-other-username" is forbidden: User "test-admin" ` + wantError: `users "some-other-username" is forbidden: User "test-admin" ` +
`cannot impersonate resource "users" in API group "" at the cluster scope: impersonation is not allowed or invalid verb`, `cannot impersonate resource "users" in API group "" at the cluster scope: impersonation is not allowed or invalid verb`,
}, },
{
name: "no bearer token file in Kube API server client config",
wantConstructionError: "invalid impersonator loopback rest config has wrong bearer token semantics",
},
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
@ -181,10 +231,16 @@ func TestImpersonator(t *testing.T) {
}() }()
// Create client certs for authentication to the impersonator. // Create client certs for authentication to the impersonator.
clientCertPEM, clientKeyPEM, err := ca.IssuePEM( var clientCertPEM, clientKeyPEM []byte
pkix.Name{CommonName: tt.clientUsername, Organization: tt.clientGroups}, nil, nil, time.Hour, if len(tt.clientCertPEM) == 0 {
) clientCertPEM, clientKeyPEM, err = ca.IssuePEM(
require.NoError(t, err) pkix.Name{CommonName: tt.clientUsername, Organization: tt.clientGroups}, nil, nil, time.Hour,
)
require.NoError(t, err)
} else {
clientCertPEM = []byte(tt.clientCertPEM)
clientKeyPEM = []byte(tt.clientKeyPEM)
}
// Create a kubeconfig to talk to the impersonator as a client. // Create a kubeconfig to talk to the impersonator as a client.
clientKubeconfig := &rest.Config{ clientKubeconfig := &rest.Config{
@ -195,7 +251,7 @@ func TestImpersonator(t *testing.T) {
KeyData: clientKeyPEM, KeyData: clientKeyPEM,
}, },
UserAgent: "test-agent", UserAgent: "test-agent",
// BearerToken should be ignored during auth because there are valid client certs, // BearerToken should be ignored during auth when there are valid client certs,
// and it should not passed into the impersonator handler func as an authorization header. // and it should not passed into the impersonator handler func as an authorization header.
BearerToken: "must-be-ignored", BearerToken: "must-be-ignored",
Impersonate: tt.clientImpersonateUser, Impersonate: tt.clientImpersonateUser,
@ -222,18 +278,7 @@ func TestImpersonator(t *testing.T) {
// The impersonator should have proxied the request to the fake Kube API server, which should have seen // The impersonator should have proxied the request to the fake Kube API server, which should have seen
// the headers of the original request mutated by the impersonator. // the headers of the original request mutated by the impersonator.
require.True(t, testKubeAPIServerWasCalled) require.True(t, testKubeAPIServerWasCalled)
require.Equal(t, require.Equal(t, tt.wantKubeAPIServerRequestHeaders, testKubeAPIServerSawHeaders)
http.Header{
"Impersonate-User": {tt.clientUsername},
"Impersonate-Group": append(tt.clientGroups, "system:authenticated"),
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
},
testKubeAPIServerSawHeaders,
)
} }
// Stop the impersonator server. // Stop the impersonator server.