Use gorilla websocket library so squid proxy works

This commit is contained in:
Margo Crawford 2021-03-10 15:49:09 -08:00
parent 006dc8aa79
commit 24396b6af1
2 changed files with 41 additions and 21 deletions

1
go.mod
View File

@ -15,6 +15,7 @@ require (
github.com/google/go-cmp v0.5.5 github.com/google/go-cmp v0.5.5
github.com/google/gofuzz v1.2.0 github.com/google/gofuzz v1.2.0
github.com/gorilla/securecookie v1.1.1 github.com/gorilla/securecookie v1.1.1
github.com/gorilla/websocket v1.4.2 // indirect
github.com/oleiade/reflections v1.0.1 // indirect github.com/oleiade/reflections v1.0.1 // indirect
github.com/onsi/ginkgo v1.13.0 // indirect github.com/onsi/ginkgo v1.13.0 // indirect
github.com/ory/fosite v0.38.0 github.com/ory/fosite v0.38.0

View File

@ -6,7 +6,6 @@ package integration
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
@ -22,8 +21,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/net/websocket"
v1 "k8s.io/api/authorization/v1" v1 "k8s.io/api/authorization/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
@ -558,30 +558,44 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
}) })
t.Run("websocket client", func(t *testing.T) { t.Run("websocket client", func(t *testing.T) {
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"},
)
// Wait for the above RBAC rule to take effect.
library.WaitForUserToHaveAccess(t, env.TestUser.ExpectedUsername, []string{}, &v1.ResourceAttributes{
Namespace: namespace.Name, Verb: "create", Group: "", Version: "v1", Resource: "configmaps",
})
impersonationRestConfig := impersonationProxyRestConfig(refreshCredential(), impersonationProxyURL, impersonationProxyCACertPEM, "")
tlsConfig, err := rest.TLSConfigFor(impersonationRestConfig)
require.NoError(t, err)
dest, _ := url.Parse(impersonationProxyURL) dest, _ := url.Parse(impersonationProxyURL)
dest.Scheme = "wss" dest.Scheme = "wss"
dest.Path = "/api/v1/namespaces/" + namespace.Name + "/configmaps" dest.Path = "/api/v1/namespaces/" + namespace.Name + "/configmaps"
dest.RawQuery = "watch=1&resourceVersion=0" dest.RawQuery = "watch=1&resourceVersion=0"
origin, _ := url.Parse("http://localhost")
rootCAs := x509.NewCertPool() dialer := websocket.Dialer{
rootCAs.AppendCertsFromPEM(impersonationProxyCACertPEM) TLSClientConfig: tlsConfig,
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: rootCAs,
} }
if !env.HasCapability(library.HasExternalLoadBalancerProvider) {
websocketConfig := websocket.Config{ dialer.Proxy = func(req *http.Request) (*url.URL, error) {
Location: dest, proxyURL, err := url.Parse(env.Proxy)
Origin: origin, require.NoError(t, err)
TlsConfig: tlsConfig, t.Logf("passing request for %s through proxy %s", req.URL, proxyURL.String())
Version: 13, return proxyURL, nil
Header: http.Header(make(map[string][]string)), }
} }
ws, err := websocket.DialConfig(&websocketConfig) c, r, err := dialer.Dial(dest.String(), nil)
if err != nil { if r != nil {
t.Fatalf("failed to dial websocket: %v", err) defer r.Body.Close()
} }
if err != nil && r != nil {
body, _ := ioutil.ReadAll(r.Body)
t.Logf("websocket dial failed: %d:%s", r.StatusCode, body)
}
require.NoError(t, err)
// perform a create through the admin client // perform a create through the admin client
_, err = adminClient.CoreV1().ConfigMaps(namespace.Name).Create(ctx, _, err = adminClient.CoreV1().ConfigMaps(namespace.Name).Create(ctx,
@ -589,17 +603,22 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
metav1.CreateOptions{}, metav1.CreateOptions{},
) )
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() {
err = adminClient.CoreV1().ConfigMaps(namespace.Name).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{})
require.NoError(t, err)
})
// see if the websocket client received an event for the create // see if the websocket client received an event for the create
var got watchJSON _, message, err := c.ReadMessage()
err = websocket.JSON.Receive(ws, &got)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
var got watchJSON
err = json.Unmarshal(message, &got)
require.NoError(t, err)
if got.Type != watch.Added { if got.Type != watch.Added {
t.Errorf("Unexpected type: %v", got.Type) t.Errorf("Unexpected type: %v", got.Type)
} }
var createConfigMap corev1.ConfigMap var createConfigMap corev1.ConfigMap
err = json.Unmarshal(got.Object, &createConfigMap) err = json.Unmarshal(got.Object, &createConfigMap)
require.NoError(t, err) require.NoError(t, err)