mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-18 22:14:22 +00:00
Fix bug which prevented watches from working through impersonator
Also: - Changed base64 encoding of impersonator bearer tokens to use `base64.StdEncoding` to make it easier for users to manually create a token using the unix `base64` command - Test the headers which are and are not passed through to the Kube API by the impersonator more carefully in the unit tests - More WIP on concierge_impersonation_proxy_test.go Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
committed by
Margo Crawford
parent
b8592a361c
commit
80ff5c1f17
@@ -12,8 +12,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -124,12 +128,94 @@ func TestImpersonationProxy(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("watching all the verbs", func(t *testing.T) {
|
||||
// Start a watch in a informer.
|
||||
// Create an RBAC rule to allow this user to read/write everything.
|
||||
// t.Cleanup Delete the RBAC rule.
|
||||
// Create a namespace, because it will be easier to deletecollection if we have a namespace.
|
||||
// t.Cleanup Delete the namespace.
|
||||
// Then "create" several Secrets.
|
||||
namespace, err := adminClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{GenerateName: "impersonation-integration-test-"},
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
t.Logf("cleaning up test namespace %s", namespace.Name)
|
||||
err = adminClient.CoreV1().Namespaces().Delete(context.Background(), namespace.Name, metav1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
// Create an RBAC rule to allow this user to read/write everything.
|
||||
library.CreateTestClusterRoleBinding(
|
||||
t,
|
||||
rbacv1.Subject{
|
||||
Kind: rbacv1.UserKind,
|
||||
APIGroup: rbacv1.GroupName,
|
||||
Name: env.TestUser.ExpectedUsername,
|
||||
},
|
||||
rbacv1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
APIGroup: rbacv1.GroupName,
|
||||
Name: "cluster-admin",
|
||||
},
|
||||
)
|
||||
library.WaitForUserToHaveAccess(t, env.TestUser.ExpectedUsername, []string{}, &v1.ResourceAttributes{
|
||||
Namespace: namespace.Name,
|
||||
Verb: "create",
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "configmaps",
|
||||
})
|
||||
|
||||
// Create and start informer.
|
||||
informerFactory := k8sinformers.NewSharedInformerFactoryWithOptions(
|
||||
impersonationProxyClient,
|
||||
0,
|
||||
k8sinformers.WithNamespace(namespace.Name))
|
||||
informer := informerFactory.Core().V1().ConfigMaps()
|
||||
informer.Informer() // makes sure that the informer will cache
|
||||
stopChannel := make(chan struct{})
|
||||
informerFactory.Start(stopChannel)
|
||||
t.Cleanup(func() {
|
||||
stopChannel <- struct{}{}
|
||||
})
|
||||
informerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
// Test "create" verb.
|
||||
_, err = impersonationProxyClient.CoreV1().ConfigMaps(namespace.Name).Create(
|
||||
ctx,
|
||||
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "configmap-1"}},
|
||||
metav1.CreateOptions{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Eventually(t, func() bool {
|
||||
_, err = informer.Lister().ConfigMaps(namespace.Name).Get("configmap-1")
|
||||
return err == nil
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
_, err = impersonationProxyClient.CoreV1().ConfigMaps(namespace.Name).Create(
|
||||
ctx,
|
||||
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "configmap-2"}},
|
||||
metav1.CreateOptions{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Eventually(t, func() bool {
|
||||
_, err = informer.Lister().ConfigMaps(namespace.Name).Get("configmap-2")
|
||||
return err == nil
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
_, err = impersonationProxyClient.CoreV1().ConfigMaps(namespace.Name).Create(
|
||||
ctx,
|
||||
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "configmap-3"}},
|
||||
metav1.CreateOptions{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Eventually(t, func() bool {
|
||||
_, err = informer.Lister().ConfigMaps(namespace.Name).Get("configmap-3")
|
||||
return err == nil
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
require.Eventually(t, func() bool {
|
||||
configmaps, err := informer.Lister().ConfigMaps(namespace.Name).List(labels.Everything())
|
||||
return err == nil && len(configmaps) == 3
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
// TODO, test more verbs
|
||||
// "get" one them.
|
||||
// "list" them all.
|
||||
// "update" one of them.
|
||||
@@ -137,7 +223,6 @@ func TestImpersonationProxy(t *testing.T) {
|
||||
// "delete" one of them.
|
||||
// "deletecollection" all of them.
|
||||
// Make sure the watch sees all of those actions.
|
||||
// Close the informer.
|
||||
})
|
||||
|
||||
// Update configuration to force the proxy to disabled mode
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/stretchr/testify/require"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
@@ -135,6 +136,12 @@ func TestE2EFullIntegration(t *testing.T) {
|
||||
rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: env.SupervisorTestUpstream.Username},
|
||||
rbacv1.RoleRef{Kind: "ClusterRole", APIGroup: rbacv1.GroupName, Name: "view"},
|
||||
)
|
||||
library.WaitForUserToHaveAccess(t, env.SupervisorTestUpstream.Username, []string{}, &authorizationv1.ResourceAttributes{
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "namespaces",
|
||||
})
|
||||
|
||||
// Use a specific session cache for this test.
|
||||
sessionCachePath := tempDir + "/sessions.yaml"
|
||||
|
||||
+14
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package library
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -137,6 +138,12 @@ func addTestClusterUserCanViewEverythingRoleBinding(t *testing.T, testUsername s
|
||||
Name: "view",
|
||||
},
|
||||
)
|
||||
WaitForUserToHaveAccess(t, testUsername, []string{}, &authorizationv1.ResourceAttributes{
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "namespaces",
|
||||
})
|
||||
}
|
||||
|
||||
func addTestClusterGroupCanViewEverythingRoleBinding(t *testing.T, testGroup string) {
|
||||
@@ -154,6 +161,12 @@ func addTestClusterGroupCanViewEverythingRoleBinding(t *testing.T, testGroup str
|
||||
Name: "view",
|
||||
},
|
||||
)
|
||||
WaitForUserToHaveAccess(t, "", []string{testGroup}, &authorizationv1.ResourceAttributes{
|
||||
Verb: "get",
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "namespaces",
|
||||
})
|
||||
}
|
||||
|
||||
func runKubectlGetNamespaces(t *testing.T, kubeConfigYAML string) (string, error) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
authorizationv1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -434,6 +435,27 @@ func CreateTestClusterRoleBinding(t *testing.T, subject rbacv1.Subject, roleRef
|
||||
return created
|
||||
}
|
||||
|
||||
func WaitForUserToHaveAccess(t *testing.T, user string, groups []string, shouldHaveAccessTo *authorizationv1.ResourceAttributes) {
|
||||
t.Helper()
|
||||
client := NewKubernetesClientset(t)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||
subjectAccessReview, err := client.AuthorizationV1().SubjectAccessReviews().Create(ctx,
|
||||
&authorizationv1.SubjectAccessReview{
|
||||
Spec: authorizationv1.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: shouldHaveAccessTo,
|
||||
User: user,
|
||||
Groups: groups,
|
||||
}}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return subjectAccessReview.Status.Allowed, nil
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
}
|
||||
|
||||
func testObjectMeta(t *testing.T, baseName string) metav1.ObjectMeta {
|
||||
return metav1.ObjectMeta{
|
||||
GenerateName: fmt.Sprintf("test-%s-", baseName),
|
||||
|
||||
Reference in New Issue
Block a user