Added integration test for using websockets via the impersonation proxy
Tested that this test passed when using the kube api server directly, so it's just the impersonation proxy that must be improved.
This commit is contained in:
parent
005133fbfb
commit
c853707889
1
go.mod
1
go.mod
@ -26,6 +26,7 @@ require (
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d // indirect
|
||||
|
2
go.sum
2
go.sum
@ -1178,6 +1178,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -6,7 +6,10 @@ package integration
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -18,6 +21,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/websocket"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/authorization/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@ -26,6 +31,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
@ -181,19 +187,20 @@ func TestImpersonationProxy(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
// Create a namespace, because it will be easier to exercise "deletecollection" if we have a namespace.
|
||||
namespace, err := adminClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{GenerateName: "impersonation-integration-test-"},
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
// Schedule the namespace for cleanup.
|
||||
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)
|
||||
})
|
||||
|
||||
// Try more Kube API verbs through the impersonation proxy.
|
||||
t.Run("watching all the basic verbs", func(t *testing.T) {
|
||||
// Create a namespace, because it will be easier to exercise "deletecollection" if we have a namespace.
|
||||
namespace, err := adminClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{GenerateName: "impersonation-integration-test-"},
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
// Schedule the namespace for cleanup.
|
||||
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,
|
||||
@ -478,6 +485,54 @@ func TestImpersonationProxy(t *testing.T) {
|
||||
require.Contains(t, curlStdOut.String(), "\"forbidden: User \\\"system:anonymous\\\" cannot get path \\\"/\\\"\"")
|
||||
})
|
||||
|
||||
t.Run("websocket client", func(t *testing.T) {
|
||||
dest, _ := url.Parse(impersonationProxyURL)
|
||||
dest.Scheme = "wss"
|
||||
dest.Path = "/api/v1/namespaces/" + namespace.Name + "/configmaps"
|
||||
dest.RawQuery = "watch=1&resourceVersion=0"
|
||||
origin, _ := url.Parse("http://localhost")
|
||||
|
||||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AppendCertsFromPEM(impersonationProxyCACertPEM)
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
}
|
||||
|
||||
websocketConfig := websocket.Config{
|
||||
Location: dest,
|
||||
Origin: origin,
|
||||
TlsConfig: tlsConfig,
|
||||
Version: 13,
|
||||
Header: http.Header(make(map[string][]string)),
|
||||
}
|
||||
ws, err := websocket.DialConfig(&websocketConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial websocket: %v", err)
|
||||
}
|
||||
|
||||
// perform a create through the admin client
|
||||
_, err = adminClient.CoreV1().ConfigMaps(namespace.Name).Create(ctx,
|
||||
&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "configmap-1"}},
|
||||
metav1.CreateOptions{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// see if the websocket client received an event for the create
|
||||
var got watchJSON
|
||||
err = websocket.JSON.Receive(ws, &got)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if got.Type != watch.Added {
|
||||
t.Errorf("Unexpected type: %v", got.Type)
|
||||
}
|
||||
|
||||
var createConfigMap corev1.ConfigMap
|
||||
err = json.Unmarshal(got.Object, &createConfigMap)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "configmap-1", createConfigMap.Name)
|
||||
})
|
||||
|
||||
// Update configuration to force the proxy to disabled mode
|
||||
configMap := configMapForConfig(t, env, impersonator.Config{Mode: impersonator.ModeDisabled})
|
||||
if env.HasCapability(library.HasExternalLoadBalancerProvider) {
|
||||
@ -649,3 +704,9 @@ func impersonationProxyLoadBalancerName(env *library.TestEnv) string {
|
||||
func credentialIssuerName(env *library.TestEnv) string {
|
||||
return env.ConciergeAppName + "-config"
|
||||
}
|
||||
|
||||
// watchJSON defines the expected JSON wire equivalent of watch.Event
|
||||
type watchJSON struct {
|
||||
Type watch.EventType `json:"type,omitempty"`
|
||||
Object json.RawMessage `json:"object,omitempty"`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user