Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2020-01-29 15:21:33 +0300
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2020-01-29 15:21:33 +0300
commit7e8b22c4070baba5425760cf7285486a8c97b335 (patch)
tree42425335e48ae596d1d9d919f9ae8d59051b541f /internal/serving
parent2afc2463559e19ee40bcb0770ce49438adca0735 (diff)
Provide a real function location when proxing serverless requests
Diffstat (limited to 'internal/serving')
-rw-r--r--internal/serving/serverless/certs.go26
-rw-r--r--internal/serving/serverless/cluster.go33
-rw-r--r--internal/serving/serverless/director.go9
-rw-r--r--internal/serving/serverless/function.go18
-rw-r--r--internal/serving/serverless/serverless.go4
-rw-r--r--internal/serving/serverless/serverless_test.go45
-rw-r--r--internal/serving/serverless/transport.go2
7 files changed, 91 insertions, 46 deletions
diff --git a/internal/serving/serverless/certs.go b/internal/serving/serverless/certs.go
new file mode 100644
index 00000000..674e8b25
--- /dev/null
+++ b/internal/serving/serverless/certs.go
@@ -0,0 +1,26 @@
+package serverless
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+)
+
+// Certs holds definition of certificates we use to perform mTLS
+// handshake with a cluster
+type Certs struct {
+ RootCerts *x509.CertPool
+ Certificate tls.Certificate
+}
+
+// NewClusterCerts creates a new cluster configuration from cert / key pair
+func NewClusterCerts(clientCert, clientKey string) (*Certs, error) {
+ cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
+ if err != nil {
+ return nil, err
+ }
+
+ caCertPool := x509.NewCertPool()
+ caCertPool.AppendCertsFromPEM([]byte(clientCert))
+
+ return &Certs{RootCerts: caCertPool, Certificate: cert}, nil
+}
diff --git a/internal/serving/serverless/cluster.go b/internal/serving/serverless/cluster.go
index b511f409..6bdd51da 100644
--- a/internal/serving/serverless/cluster.go
+++ b/internal/serving/serverless/cluster.go
@@ -2,35 +2,20 @@ package serverless
import (
"crypto/tls"
- "crypto/x509"
+ "strings"
)
// Cluster represent a Knative cluster that we want to proxy requests to
type Cluster struct {
- Address string
- Port string
- Hostname string
- Certs *ClusterCerts
+ Address string // Address is a real IP address of a cluster ingress
+ Port string // Port is a real port of HTTP TLS service
+ Name string // Name is a cluster name, used in cluster certificates
+ Certs *Certs
}
-// ClusterCerts holds definition of certificates we use to perform mTLS
-// handshake
-type ClusterCerts struct {
- RootCerts *x509.CertPool
- Certificate tls.Certificate
-}
-
-// NewClusterCerts creates a new cluster configuration from cert / key pair
-func NewClusterCerts(clientCert, clientKey string) (*ClusterCerts, error) {
- cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
- if err != nil {
- return nil, err
- }
-
- caCertPool := x509.NewCertPool()
- caCertPool.AppendCertsFromPEM([]byte(clientCert))
-
- return &ClusterCerts{RootCerts: caCertPool, Certificate: cert}, nil
+// Host returns a real cluster location based on IP address and port
+func (c Cluster) Host() string {
+ return strings.Join([]string{c.Address, c.Port}, ":")
}
// TLSConfig builds a new tls.Config and returns a pointer to it
@@ -38,6 +23,6 @@ func (c Cluster) TLSConfig() *tls.Config {
return &tls.Config{
Certificates: []tls.Certificate{c.Certs.Certificate},
RootCAs: c.Certs.RootCerts,
- ServerName: c.Hostname,
+ ServerName: c.Name,
}
}
diff --git a/internal/serving/serverless/director.go b/internal/serving/serverless/director.go
index 68887a13..4478b104 100644
--- a/internal/serving/serverless/director.go
+++ b/internal/serving/serverless/director.go
@@ -2,19 +2,18 @@ package serverless
import (
"net/http"
- "strings"
"github.com/tomasen/realip"
)
// NewDirectorFunc returns a director function capable of configuring a proxy
// request
-func NewDirectorFunc(cluster Cluster) func(*http.Request) {
+func NewDirectorFunc(function Function) func(*http.Request) {
return func(request *http.Request) {
- location := strings.Join([]string{cluster.Address, cluster.Port}, ":")
+ host := function.Host()
- request.Host = location
- request.URL.Host = location
+ request.Host = host
+ request.URL.Host = host
request.URL.Scheme = "https"
request.Header.Set("User-Agent", "GitLab Pages Daemon")
request.Header.Set("X-Forwarded-For", realip.FromRequest(request))
diff --git a/internal/serving/serverless/function.go b/internal/serving/serverless/function.go
new file mode 100644
index 00000000..20d4ec2c
--- /dev/null
+++ b/internal/serving/serverless/function.go
@@ -0,0 +1,18 @@
+package serverless
+
+import "strings"
+
+// Function represents a Knative service that is going to be invoked by the
+// proxied request
+type Function struct {
+ Name string // Name is a function name, it includes a "service name" component too
+ Namespace string // Namespace is a kubernetes namespace this function has been deployed to
+ BaseDomain string // BaseDomain is a cluster base domain, used to route requests to apropriate service
+}
+
+// Host returns a function address that we are going to expose in the `Host:`
+// header to make it possible to route a proxied request to appropriate service
+// in a Knative cluster
+func (f Function) Host() string {
+ return strings.Join([]string{f.Name, f.Namespace, f.BaseDomain}, ".")
+}
diff --git a/internal/serving/serverless/serverless.go b/internal/serving/serverless/serverless.go
index 3b7b7d43..a8d090da 100644
--- a/internal/serving/serverless/serverless.go
+++ b/internal/serving/serverless/serverless.go
@@ -14,9 +14,9 @@ type Serverless struct {
}
// New returns a new serving instance
-func New(cluster Cluster) serving.Serving {
+func New(function Function, cluster Cluster) serving.Serving {
proxy := httputil.ReverseProxy{
- Director: NewDirectorFunc(cluster),
+ Director: NewDirectorFunc(function),
Transport: NewTransport(cluster),
ErrorHandler: NewErrorHandler(),
}
diff --git a/internal/serving/serverless/serverless_test.go b/internal/serving/serverless/serverless_test.go
index 96627d7a..2d0b7df0 100644
--- a/internal/serving/serverless/serverless_test.go
+++ b/internal/serving/serverless/serverless_test.go
@@ -15,7 +15,7 @@ import (
"gitlab.com/gitlab-org/gitlab-pages/internal/serving"
)
-func withTestCluster(t *testing.T, cert, key string, block func(*http.ServeMux, *url.URL, *ClusterCerts)) {
+func withTestCluster(t *testing.T, cert, key string, block func(*http.ServeMux, *url.URL, *Certs)) {
mux := http.NewServeMux()
cluster := httptest.NewUnstartedServer(mux)
@@ -38,13 +38,20 @@ func withTestCluster(t *testing.T, cert, key string, block func(*http.ServeMux,
func TestServeFileHTTP(t *testing.T) {
t.Run("when proxying simple request to a cluster", func(t *testing.T) {
- withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *ClusterCerts) {
- serverless := New(Cluster{
- Hostname: "knative.gitlab-example.com",
- Address: server.Hostname(),
- Port: server.Port(),
- Certs: certs,
- })
+ withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) {
+ serverless := New(
+ Function{
+ Name: "my-func",
+ Namespace: "my-namespace-123",
+ BaseDomain: "knative.example.com",
+ },
+ Cluster{
+ Name: "knative.gitlab-example.com",
+ Address: server.Hostname(),
+ Port: server.Port(),
+ Certs: certs,
+ },
+ )
writer := httptest.NewRecorder()
request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil)
@@ -52,6 +59,7 @@ func TestServeFileHTTP(t *testing.T) {
request.Header.Set("X-Real-IP", "127.0.0.105")
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ assert.Equal(t, "my-func.my-namespace-123.knative.example.com", r.Host)
assert.Equal(t, "GitLab Pages Daemon", r.Header.Get("User-Agent"))
assert.Equal(t, "https", r.Header.Get("X-Forwarded-Proto"))
assert.Contains(t, r.Header.Get("X-Forwarded-For"), "127.0.0.105")
@@ -66,13 +74,20 @@ func TestServeFileHTTP(t *testing.T) {
})
t.Run("when proxying request with invalid hostname", func(t *testing.T) {
- withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *ClusterCerts) {
- serverless := New(Cluster{
- Hostname: "knative.invalid-gitlab-example.com",
- Address: server.Hostname(),
- Port: server.Port(),
- Certs: certs,
- })
+ withTestCluster(t, fixture.Certificate, fixture.Key, func(mux *http.ServeMux, server *url.URL, certs *Certs) {
+ serverless := New(
+ Function{
+ Name: "my-func",
+ Namespace: "my-namespace-123",
+ BaseDomain: "knative.example.com",
+ },
+ Cluster{
+ Name: "knative.invalid-gitlab-example.com",
+ Address: server.Hostname(),
+ Port: server.Port(),
+ Certs: certs,
+ },
+ )
writer := httptest.NewRecorder()
request := httptest.NewRequest("GET", "http://example.gitlab.com/", nil)
diff --git a/internal/serving/serverless/transport.go b/internal/serving/serverless/transport.go
index d98663f5..98a5473e 100644
--- a/internal/serving/serverless/transport.go
+++ b/internal/serving/serverless/transport.go
@@ -22,6 +22,8 @@ func NewTransport(cluster Cluster) *Transport {
}
dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
+ address = cluster.Host()
+
return dialer.DialContext(ctx, network, address)
}