diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2020-01-16 18:33:30 +0300 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2020-01-28 13:33:17 +0300 |
commit | 0509d6b4aa276d0a61592f5ad9d464f13c8e458f (patch) | |
tree | 1e554394fa6b79c6479590e2284cee9c0f798b5a /internal | |
parent | 4317f67bea77be4cfce36a7454e15f888a2d9ea2 (diff) |
Add initial implementation of serverless proxy
Diffstat (limited to 'internal')
-rw-r--r-- | internal/serving/serverless/cluster.go | 38 | ||||
-rw-r--r-- | internal/serving/serverless/director.go | 17 | ||||
-rw-r--r-- | internal/serving/serverless/serverless.go | 10 | ||||
-rw-r--r-- | internal/serving/serverless/serverless_test.go | 50 | ||||
-rw-r--r-- | internal/serving/serverless/transport.go | 3 |
5 files changed, 103 insertions, 15 deletions
diff --git a/internal/serving/serverless/cluster.go b/internal/serving/serverless/cluster.go index d8eb6696..3912fc73 100644 --- a/internal/serving/serverless/cluster.go +++ b/internal/serving/serverless/cluster.go @@ -1,5 +1,43 @@ package serverless +import ( + "crypto/tls" + "crypto/x509" +) + // Cluster represent a Knative cluster that we want to proxy requests to type Cluster struct { + Address string + Hostname string + Port string + Config *Config +} + +// Config holds configuration for a cluster, especially definition of +// certificates we use to perform mTLS handshake +type Config struct { + RootCerts *x509.CertPool + Certificate tls.Certificate +} + +// NewClusterConfig creates a new cluster configuration from cert / key pair +func NewClusterConfig(clientCert, clientKey string) (*Config, error) { + cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey)) + if err != nil { + return nil, err + } + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM([]byte(clientCert)) + + return &Config{RootCerts: caCertPool, Certificate: cert}, nil +} + +// TLSConfig builds a new tls.Config and returns a pointer to it +func (c Cluster) TLSConfig() *tls.Config { + return &tls.Config{ + Certificates: []tls.Certificate{c.Config.Certificate}, + RootCAs: c.Config.RootCerts, + ServerName: c.Hostname, + } } diff --git a/internal/serving/serverless/director.go b/internal/serving/serverless/director.go index 83398c0e..83d792c3 100644 --- a/internal/serving/serverless/director.go +++ b/internal/serving/serverless/director.go @@ -1,15 +1,18 @@ package serverless -import "net/http" +import ( + "net/http" + "strings" +) // NewDirectorFunc returns a director function capable of configuring a proxy // request func NewDirectorFunc(cluster Cluster) func(*http.Request) { - return func(r *http.Request) { - // request.Host = domain - // request.URL.Host = domain - // request.URL.Scheme = "https" - // request.Header.Set("User-Agent", "ReverseProxy PoC") - // request.Header.Set("X-Forwarded ...") + return func(request *http.Request) { + request.Host = cluster.Address + request.URL.Host = strings.Join([]string{cluster.Address, cluster.Port}, ":") + request.URL.Scheme = "https" + request.Header.Set("User-Agent", "GitLab Pages Daemon") + request.Header.Set("X-Forwarded-For", "123") // TODO } } diff --git a/internal/serving/serverless/serverless.go b/internal/serving/serverless/serverless.go index 96a3a996..77150996 100644 --- a/internal/serving/serverless/serverless.go +++ b/internal/serving/serverless/serverless.go @@ -1,7 +1,6 @@ package serverless import ( - "net/http" "net/http/httputil" "gitlab.com/gitlab-org/gitlab-pages/internal/httperrors" @@ -26,15 +25,12 @@ func New(cluster Cluster) serving.Serving { // ServeFileHTTP handle an incoming request and proxies it to Knative cluster func (s *Serverless) ServeFileHTTP(h serving.Handler) bool { - return false + s.proxy.ServeHTTP(h.Writer, h.Request) + + return true } // ServeNotFoundHTTP responds with 404 func (s *Serverless) ServeNotFoundHTTP(h serving.Handler) { httperrors.Serve404(h.Writer) } - -func (s *Serverless) director() func(request *http.Request) { - return func(request *http.Request) { - } -} diff --git a/internal/serving/serverless/serverless_test.go b/internal/serving/serverless/serverless_test.go new file mode 100644 index 00000000..169f3de5 --- /dev/null +++ b/internal/serving/serverless/serverless_test.go @@ -0,0 +1,50 @@ +package serverless + +import ( + "crypto/tls" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "gitlab.com/gitlab-org/gitlab-pages/internal/fixture" + "gitlab.com/gitlab-org/gitlab-pages/internal/serving" +) + +func TestServeFileHTTP(t *testing.T) { + config, err := NewClusterConfig(fixture.Certificate, fixture.Key) + require.NoError(t, err) + + cluster := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "GitLab Pages Daemon", r.Header.Get("User-Agent")) + })) + + cluster.TLS = &tls.Config{ + Certificates: []tls.Certificate{config.Certificate}, + RootCAs: config.RootCerts, + } + + cluster.StartTLS() + defer cluster.Close() + + clusterURL, err := url.Parse(cluster.URL) + require.NoError(t, err) + + serverless := New(Cluster{ + Address: clusterURL.Hostname(), + Hostname: "knative.gitlab-example.com", + Port: clusterURL.Port(), + Config: config, + }) + + t.Run("when proxying simple request to a cluster", func(t *testing.T) { + writer := httptest.NewRecorder() + request := httptest.NewRequest("GET", "http://example.gitlab.com", nil) + handler := serving.Handler{Writer: writer, Request: request} + + assert.True(t, serverless.ServeFileHTTP(handler)) + }) +} diff --git a/internal/serving/serverless/transport.go b/internal/serving/serverless/transport.go index 7cd3e03d..8d195688 100644 --- a/internal/serving/serverless/transport.go +++ b/internal/serving/serverless/transport.go @@ -31,10 +31,11 @@ func NewTransport(cluster Cluster) *Transport { } return &Transport{ + cluster: cluster, transport: &http.Transport{ DialContext: dialContext, TLSHandshakeTimeout: 5 * time.Second, - // TODO TLSClientConfig: newTLSConfig(), + TLSClientConfig: cluster.TLSConfig(), }, } } |