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

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavlo Strokov <pstrokov@gitlab.com>2020-06-18 13:02:56 +0300
committerPavlo Strokov <pstrokov@gitlab.com>2020-07-01 17:01:42 +0300
commitb41efd6feb6d2a241528ded7f604f765a4c4ec25 (patch)
tree3f7a0479bebdeee2003cf2aa49c6aaa03517f76b /internal/praefect/metadata
parent715cfcc7c66040149447ecdfb2400d0494c88b47 (diff)
Add TLS support to Praefect
Praefect allowed to use TLS address to listen on in combination with certificate and its key to be used for it. 'metadata' package refactored, so TLS address can be passed into the Gitaly. Documentation fixed and example file filled with proper vals. Closes: https://gitlab.com/gitlab-org/gitaly/-/issues/1698
Diffstat (limited to 'internal/praefect/metadata')
-rw-r--r--internal/praefect/metadata/server.go115
-rw-r--r--internal/praefect/metadata/server_test.go48
2 files changed, 131 insertions, 32 deletions
diff --git a/internal/praefect/metadata/server.go b/internal/praefect/metadata/server.go
index 1c88a6b9e..1a19a1e6f 100644
--- a/internal/praefect/metadata/server.go
+++ b/internal/praefect/metadata/server.go
@@ -7,12 +7,15 @@ import (
"errors"
"fmt"
"net"
+ "net/url"
"strings"
gitalyauth "gitlab.com/gitlab-org/gitaly/auth"
"gitlab.com/gitlab-org/gitaly/client"
+ "gitlab.com/gitlab-org/gitaly/internal/bootstrap/starter"
"gitlab.com/gitlab-org/gitaly/internal/praefect/config"
"google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
)
@@ -36,6 +39,8 @@ var (
type PraefectServer struct {
// ListenAddr is the TCP listen address of the Praefect server
ListenAddr string `json:"listen_addr"`
+ // TLSListenAddr is the TCP listen address of the Praefect server with TLS support
+ TLSListenAddr string `json:"tls_listen_addr"`
// SocketPath is the Unix socket path of the Praefect server
SocketPath string `json:"socket_path"`
// Token is the token required to authenticate with the Praefect server
@@ -44,10 +49,40 @@ type PraefectServer struct {
// InjectPraefectServer injects Praefect connection metadata into an incoming context
func InjectPraefectServer(ctx context.Context, conf config.Config) (context.Context, error) {
- praefectServer := PraefectServer{
- ListenAddr: strings.TrimPrefix(conf.ListenAddr, "tcp://"),
- SocketPath: strings.TrimPrefix(conf.SocketPath, "unix://"),
- Token: conf.Auth.Token,
+ praefectServer := PraefectServer{Token: conf.Auth.Token}
+
+ addrBySchema := map[string]*string{
+ starter.TCP: &praefectServer.ListenAddr,
+ starter.TLS: &praefectServer.TLSListenAddr,
+ starter.Unix: &praefectServer.SocketPath,
+ }
+
+ for _, endpoint := range []struct {
+ schema string
+ addr string
+ }{
+ {schema: starter.TCP, addr: conf.ListenAddr},
+ {schema: starter.TLS, addr: conf.TLSListenAddr},
+ {schema: starter.Unix, addr: conf.SocketPath},
+ } {
+ if endpoint.addr == "" {
+ continue
+ }
+
+ parsed, err := starter.ParseEndpoint(endpoint.addr)
+ if err != nil {
+ if !errors.Is(err, starter.ErrEmptySchema) {
+ return nil, err
+ }
+ parsed = starter.Config{Name: endpoint.schema, Addr: endpoint.addr}
+ }
+
+ addr, err := parsed.Endpoint()
+ if err != nil {
+ return nil, fmt.Errorf("processing of %s: %w", endpoint.schema, err)
+ }
+
+ *addrBySchema[endpoint.schema] = addr
}
marshalled, err := json.Marshal(praefectServer)
@@ -77,29 +112,61 @@ func (p *PraefectServer) resolvePraefectAddress(peer *peer.Peer) error {
}
p.ListenAddr = ""
+ p.TLSListenAddr = ""
+
return nil
case *net.TCPAddr:
- if p.ListenAddr == "" {
- return errors.New("resolvePraefectAddress: got TCP peer but no listen address")
- }
-
- // We need to replace Praefect's IP address with the peer's
- // address as the value we have is from Praefect's configuration,
- // which may be a wildcard IP address ("0.0.0.0").
- _, port, err := net.SplitHostPort(p.ListenAddr)
- if err != nil {
- return fmt.Errorf("resolvePraefectAddress: could not resolve address %q: %w", p.ListenAddr, err)
+ if peer.AuthInfo == nil {
+ // no transport security being used
+ addr, err := substituteListeningWithIP(p.ListenAddr, addr.IP.String())
+ if err != nil {
+ return fmt.Errorf("resolvePraefectAddress: for ListenAddr: %w", err)
+ }
+
+ p.ListenAddr = addr
+ p.TLSListenAddr = ""
+ p.SocketPath = ""
+
+ return nil
+ } else {
+ authType := peer.AuthInfo.AuthType()
+ if authType != (credentials.TLSInfo{}).AuthType() {
+ return fmt.Errorf("resolvePraefectAddress: got TCP peer but with unknown transport security type %q", authType)
+ }
+
+ addr, err := substituteListeningWithIP(p.TLSListenAddr, addr.IP.String())
+ if err != nil {
+ return fmt.Errorf("resolvePraefectAddress: for TLSListenAddr: %w", err)
+ }
+
+ p.TLSListenAddr = addr
+ p.ListenAddr = ""
+ p.SocketPath = ""
+
+ return nil
}
-
- p.ListenAddr = net.JoinHostPort(addr.IP.String(), port)
- p.SocketPath = ""
-
- return nil
default:
return fmt.Errorf("resolvePraefectAddress: unknown peer address scheme: %s", peer.Addr.Network())
}
}
+func substituteListeningWithIP(listenAddr, ip string) (string, error) {
+ if listenAddr == "" {
+ return "", errors.New("listening address is empty")
+ }
+
+ // We need to replace Praefect's IP address with the peer's
+ // address as the value we have is from Praefect's configuration,
+ // which may be a wildcard IP address ("0.0.0.0").
+ listenURL, err := url.Parse(listenAddr)
+ if err != nil {
+ return "", fmt.Errorf("parse listening address %q: %w", listenAddr, err)
+ }
+
+ listenURL.Host = net.JoinHostPort(ip, listenURL.Port())
+ return listenURL.String(), nil
+}
+
// PraefectFromContext extracts `PraefectServer` from an incoming context. In
// case the metadata key is not set, the function will return `ErrPraefectServerNotFound`.
func PraefectFromContext(ctx context.Context) (*PraefectServer, error) {
@@ -176,12 +243,10 @@ func (p *PraefectServer) Env() (string, error) {
}
func (p *PraefectServer) Address() (string, error) {
- if p.SocketPath != "" {
- return "unix://" + p.SocketPath, nil
- }
-
- if p.ListenAddr != "" {
- return "tcp://" + p.ListenAddr, nil
+ for _, addr := range []string{p.SocketPath, p.TLSListenAddr, p.ListenAddr} {
+ if addr != "" {
+ return addr, nil
+ }
}
return "", errors.New("no address configured")
diff --git a/internal/praefect/metadata/server_test.go b/internal/praefect/metadata/server_test.go
index 649d6e5c9..9518d5d54 100644
--- a/internal/praefect/metadata/server_test.go
+++ b/internal/praefect/metadata/server_test.go
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/internal/praefect/config"
"gitlab.com/gitlab-org/gitaly/internal/testhelper"
+ "google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"
)
@@ -22,6 +23,19 @@ func tcpPeer(t *testing.T, ip string, port int) *peer.Peer {
}
}
+func tlsPeer(t *testing.T, ip string, port int) *peer.Peer {
+ parsedAddress := net.ParseIP(ip)
+ require.NotNil(t, parsedAddress)
+
+ return &peer.Peer{
+ Addr: &net.TCPAddr{
+ IP: parsedAddress,
+ Port: port,
+ },
+ AuthInfo: credentials.TLSInfo{},
+ }
+}
+
func unixPeer(t *testing.T, socket string) *peer.Peer {
return &peer.Peer{
Addr: &net.UnixAddr{
@@ -32,11 +46,12 @@ func unixPeer(t *testing.T, socket string) *peer.Peer {
func TestPraefect_InjectMetadata(t *testing.T) {
testcases := []struct {
- desc string
- listenAddress string
- socketPath string
- peer *peer.Peer
- expectedAddress string
+ desc string
+ listenAddress string
+ tlsListenAddress string
+ socketPath string
+ peer *peer.Peer
+ expectedAddress string
}{
{
desc: "wildcard listen address",
@@ -57,6 +72,18 @@ func TestPraefect_InjectMetadata(t *testing.T) {
expectedAddress: "tcp://1.2.3.4:1234",
},
{
+ desc: "explicit TLS listen address",
+ tlsListenAddress: "127.0.0.1:1234",
+ peer: tlsPeer(t, "1.2.3.4", 4321),
+ expectedAddress: "tls://1.2.3.4:1234",
+ },
+ {
+ desc: "explicit TLS listen address with explicit prefix",
+ tlsListenAddress: "tls://127.0.0.1:1234",
+ peer: tlsPeer(t, "1.2.3.4", 4321),
+ expectedAddress: "tls://1.2.3.4:1234",
+ },
+ {
desc: "named host listen address",
listenAddress: "example.com:1234",
peer: tcpPeer(t, "1.2.3.4", 4321),
@@ -106,6 +133,12 @@ func TestPraefect_InjectMetadata(t *testing.T) {
peer: tcpPeer(t, "1.2.3.4", 4321),
expectedAddress: "",
},
+ {
+ desc: "socket path with TLS peer",
+ socketPath: "/tmp/socket",
+ peer: tlsPeer(t, "1.2.3.4", 4321),
+ expectedAddress: "",
+ },
}
for _, tc := range testcases {
@@ -114,8 +147,9 @@ func TestPraefect_InjectMetadata(t *testing.T) {
defer cancel()
cfg := config.Config{
- ListenAddr: tc.listenAddress,
- SocketPath: tc.socketPath,
+ ListenAddr: tc.listenAddress,
+ TLSListenAddr: tc.tlsListenAddress,
+ SocketPath: tc.socketPath,
}
ctx = peer.NewContext(ctx, tc.peer)