diff --git a/changelogs/unreleased/gitaly-tls.yml b/changelogs/unreleased/gitaly-tls.yml new file mode 100644 index 0000000000000000000000000000000000000000..d54147da6c787e44028ee8a422552c4e7ca9b5d6 --- /dev/null +++ b/changelogs/unreleased/gitaly-tls.yml @@ -0,0 +1,5 @@ +--- +title: Add tls configuration to gitaly golang server +merge_request: 932 +author: +type: added diff --git a/client/address_parser.go b/client/address_parser.go index 312a7963abd8d44384b27946fa9f23a6d51c6915..55969e909be60541ed403b5f9cb80a1aa828537f 100644 --- a/client/address_parser.go +++ b/client/address_parser.go @@ -13,9 +13,9 @@ func parseAddress(rawAddress string) (canonicalAddress string, err error) { // tcp:// addresses are a special case which `grpc.Dial` expects in a // different format - if u.Scheme == "tcp" { + if u.Scheme == "tcp" || u.Scheme == "tls" { if u.Path != "" { - return "", fmt.Errorf("tcp addresses should not have a path") + return "", fmt.Errorf("%s addresses should not have a path", u.Scheme) } return u.Host, nil } diff --git a/client/address_parser_test.go b/client/address_parser_test.go index d840d1d05ace708b8aa87fb99abb6a0b616bbcfb..820a902b3c4fd4365a6890800f7998c26a517fab 100644 --- a/client/address_parser_test.go +++ b/client/address_parser_test.go @@ -20,6 +20,7 @@ func TestParseAddress(t *testing.T) { {raw: "tcp://foobar", canonical: "foobar"}, {raw: "tcp://foobar:567", canonical: "foobar:567"}, {raw: "tcp://1.2.3.4/foo/bar.socket", invalid: true}, + {raw: "tls://1.2.3.4/foo/bar.socket", invalid: true}, {raw: "tcp:///foo/bar.socket", invalid: true}, {raw: "tcp:/foo/bar.socket", invalid: true}, {raw: "tcp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9999", canonical: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:9999"}, diff --git a/client/dial.go b/client/dial.go index ff9ce206eeac3c80d3c7e1746f48cf3f3a42b2fe..e8a3a5f442145fca044c0dbd32d2d5a5f51e01ed 100644 --- a/client/dial.go +++ b/client/dial.go @@ -1,13 +1,17 @@ package client import ( + "crypto/x509" + + "google.golang.org/grpc/credentials" + + "net/url" + "google.golang.org/grpc" ) // DefaultDialOpts hold the default DialOptions for connection to Gitaly over UNIX-socket -var DefaultDialOpts = []grpc.DialOption{ - grpc.WithInsecure(), -} +var DefaultDialOpts = []grpc.DialOption{} // Dial gitaly func Dial(rawAddress string, connOpts []grpc.DialOption) (*grpc.ClientConn, error) { @@ -16,6 +20,18 @@ func Dial(rawAddress string, connOpts []grpc.DialOption) (*grpc.ClientConn, erro return nil, err } + if isTLS(rawAddress) { + certPool, err := x509.SystemCertPool() + if err != nil { + return nil, err + } + + creds := credentials.NewClientTLSFromCert(certPool, "") + connOpts = append(connOpts, grpc.WithTransportCredentials(creds)) + } else { + connOpts = append(connOpts, grpc.WithInsecure()) + } + conn, err := grpc.Dial(canonicalAddress, connOpts...) if err != nil { return nil, err @@ -23,3 +39,8 @@ func Dial(rawAddress string, connOpts []grpc.DialOption) (*grpc.ClientConn, erro return conn, nil } + +func isTLS(rawAddress string) bool { + u, err := url.Parse(rawAddress) + return err == nil && u.Scheme == "tls" +} diff --git a/cmd/gitaly-ssh/auth_test.go b/cmd/gitaly-ssh/auth_test.go index 58ff89d9a571d04396bc10f737461f940a40469b..83a6bc9ac487e39ea0efb1a57e91d27183270987 100644 --- a/cmd/gitaly-ssh/auth_test.go +++ b/cmd/gitaly-ssh/auth_test.go @@ -13,6 +13,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb" + "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/rubyserver" "gitlab.com/gitlab-org/gitaly/internal/server" "gitlab.com/gitlab-org/gitaly/internal/testhelper" @@ -26,19 +27,30 @@ func buildGitalySSH(t *testing.T) { } func TestConnectivity(t *testing.T) { - buildGitalySSH(t) - testRepo := testhelper.TestRepository() + config.Config.TLS = config.TLS{ + CertPath: "testdata/certs/gitalycert.pem", + KeyPath: "testdata/gitalykey.pem", + } cwd, err := os.Getwd() require.NoError(t, err) + + certPoolPath := path.Join(cwd, "testdata/certs") + + buildGitalySSH(t) + testRepo := testhelper.TestRepository() + gitalySSHPath := path.Join(cwd, "gitaly-ssh") socketPath := testhelper.GetTemporaryGitalySocketFileName() - tcpServer, tcpPort := runServer(t, server.New, "tcp", "localhost:0") + tcpServer, tcpPort := runServer(t, server.NewInsecure, "tcp", "localhost:0") defer tcpServer.Stop() - unixServer, _ := runServer(t, server.New, "unix", socketPath) + tlsServer, tlsPort := runServer(t, server.NewSecure, "tcp", "localhost:0") + defer tlsServer.Stop() + + unixServer, _ := runServer(t, server.NewInsecure, "unix", socketPath) defer unixServer.Stop() testCases := []struct { @@ -50,6 +62,9 @@ func TestConnectivity(t *testing.T) { { addr: fmt.Sprintf("unix://%s", socketPath), }, + { + addr: fmt.Sprintf("tls://localhost:%d", tlsPort), + }, } pbMarshaler := &jsonpb.Marshaler{} @@ -66,6 +81,7 @@ func TestConnectivity(t *testing.T) { fmt.Sprintf("GITALY_ADDRESS=%s", testcase.addr), fmt.Sprintf("PATH=.:%s", os.Getenv("PATH")), fmt.Sprintf("GIT_SSH_COMMAND=%s upload-pack", gitalySSHPath), + fmt.Sprintf("SSL_CERT_DIR=%s", certPoolPath), } output, err := cmd.Output() diff --git a/cmd/gitaly-ssh/testdata/certs/gitalycert.pem b/cmd/gitaly-ssh/testdata/certs/gitalycert.pem new file mode 100755 index 0000000000000000000000000000000000000000..8b151454896b7626b48eb325ac2e23e0edf34eac --- /dev/null +++ b/cmd/gitaly-ssh/testdata/certs/gitalycert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +YcyGxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/cmd/gitaly-ssh/testdata/gitalykey.pem b/cmd/gitaly-ssh/testdata/gitalykey.pem new file mode 100644 index 0000000000000000000000000000000000000000..8df87e63353e442e6bf028f9a0d66e1687980760 --- /dev/null +++ b/cmd/gitaly-ssh/testdata/gitalykey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +eM9aMpgdAlLOJrfZHS3kK3968ZclB4GB +-----END PRIVATE KEY----- diff --git a/cmd/gitaly/main.go b/cmd/gitaly/main.go index 9bacea720f4a88f481ddfa0b37219d93ceb274cd..c12defa28e5c0b7d776575886ecd547f16116c95 100644 --- a/cmd/gitaly/main.go +++ b/cmd/gitaly/main.go @@ -106,7 +106,8 @@ func main() { tempdir.StartCleaning() - var listeners []net.Listener + var insecureListeners []net.Listener + var secureListeners []net.Listener if socketPath := config.Config.SocketPath; socketPath != "" { l, err := createUnixListener(socketPath) @@ -114,7 +115,7 @@ func main() { log.WithError(err).Fatal("configure unix listener") } log.WithField("address", socketPath).Info("listening on unix socket") - listeners = append(listeners, l) + insecureListeners = append(insecureListeners, l) } if addr := config.Config.ListenAddr; addr != "" { @@ -124,7 +125,16 @@ func main() { } log.WithField("address", addr).Info("listening at tcp address") - listeners = append(listeners, connectioncounter.New("tcp", l)) + insecureListeners = append(insecureListeners, connectioncounter.New("tcp", l)) + } + + if addr := config.Config.TLSListenAddr; addr != "" { + tlsListener, err := net.Listen("tcp", addr) + if err != nil { + log.WithError(err).Fatal("configure tls listener") + } + + secureListeners = append(secureListeners, connectioncounter.New("tls", tlsListener)) } if config.Config.PrometheusListenAddr != "" { @@ -139,7 +149,7 @@ func main() { }() } - log.WithError(run(listeners)).Fatal("shutting down") + log.WithError(run(insecureListeners, secureListeners)).Fatal("shutting down") } func createUnixListener(socketPath string) (net.Listener, error) { @@ -152,7 +162,7 @@ func createUnixListener(socketPath string) (net.Listener, error) { // Inside here we can use deferred functions. This is needed because // log.Fatal bypasses deferred functions. -func run(listeners []net.Listener) error { +func run(insecureListeners, secureListeners []net.Listener) error { signals := []os.Signal{syscall.SIGTERM, syscall.SIGINT} termCh := make(chan os.Signal, len(signals)) signal.Notify(termCh, signals...) @@ -163,16 +173,29 @@ func run(listeners []net.Listener) error { } defer ruby.Stop() - server := server.New(ruby) - defer server.Stop() + serverErrors := make(chan error, len(insecureListeners)+len(secureListeners)) + if len(insecureListeners) > 0 { + insecureServer := server.NewInsecure(ruby) + defer insecureServer.Stop() + + for _, listener := range insecureListeners { + // Must pass the listener as a function argument because there is a race + // between 'go' and 'for'. + go func(l net.Listener) { + serverErrors <- insecureServer.Serve(l) + }(listener) + } + } - serverErrors := make(chan error, len(listeners)) - for _, listener := range listeners { - // Must pass the listener as a function argument because there is a race - // between 'go' and 'for'. - go func(l net.Listener) { - serverErrors <- server.Serve(l) - }(listener) + if len(secureListeners) > 0 { + secureServer := server.NewSecure(ruby) + defer secureServer.Stop() + + for _, listener := range secureListeners { + go func(l net.Listener) { + serverErrors <- secureServer.Serve(l) + }(listener) + } } select { diff --git a/config.toml.example b/config.toml.example index 2818531d57c1a1291e20187f11114b5df2fd0c47..1ab0fe7d6b64edf3d9fe5845b963d9c2704fc5a4 100644 --- a/config.toml.example +++ b/config.toml.example @@ -7,6 +7,7 @@ bin_dir = "/home/git/gitaly" # # Optional: listen on a TCP socket. This is insecure (no authentication) # listen_addr = "localhost:9999" +# tls_listen_addr = "localhost:8888 # # Optional: export metrics via Prometheus # prometheus_listen_addr = "localhost:9236" @@ -16,6 +17,10 @@ bin_dir = "/home/git/gitaly" # token = 'abc123secret' # transitioning = false # Set `transitioning` to true to temporarily allow unauthenticated while rolling out authentication. +# [tls] +# certificate_path = '/home/git/cert.cert' +# key_path = '/home/git/key.pem' + # # Git executable settings # [git] # bin_path = "/usr/bin/git" diff --git a/internal/config/config.go b/internal/config/config.go index 9e8ed6566bbfeedf74002d224b15ff676b135486..2145c2857b870e59b6abced03cf1be8653d9286a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,6 +21,7 @@ var ( type config struct { SocketPath string `toml:"socket_path" split_words:"true"` ListenAddr string `toml:"listen_addr" split_words:"true"` + TLSListenAddr string `toml:"tls_listen_addr" split_words:"true"` PrometheusListenAddr string `toml:"prometheus_listen_addr" split_words:"true"` BinDir string `toml:"bin_dir"` Git Git `toml:"git" envconfig:"git"` @@ -28,11 +29,18 @@ type config struct { Logging Logging `toml:"logging" envconfig:"logging"` Prometheus Prometheus `toml:"prometheus"` Auth Auth `toml:"auth"` + TLS TLS `toml:"tls"` Ruby Ruby `toml:"gitaly-ruby"` GitlabShell GitlabShell `toml:"gitlab-shell"` Concurrency []Concurrency `toml:"concurrency"` } +// TLS configuration +type TLS struct { + CertPath string `toml:"certificate_path"` + KeyPath string `toml:"key_path"` +} + // GitlabShell contains the settings required for executing `gitlab-shell` type GitlabShell struct { Dir string `toml:"dir"` diff --git a/internal/server/auth_test.go b/internal/server/auth_test.go index 483d3be3495eaf841e659170fb5f80bbcde8d6e0..9448df1342d47ba9419cec4926308c9474d84fef 100644 --- a/internal/server/auth_test.go +++ b/internal/server/auth_test.go @@ -1,6 +1,8 @@ package server import ( + "crypto/x509" + "io/ioutil" "net" "testing" @@ -12,6 +14,7 @@ import ( netctx "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" healthpb "google.golang.org/grpc/health/grpc_health_v1" ) @@ -29,6 +32,31 @@ func TestSanity(t *testing.T) { require.NoError(t, healthCheck(conn)) } +func TestTLSSanity(t *testing.T) { + srv, addr := runSecureServer(t) + defer srv.Stop() + + certPool, err := x509.SystemCertPool() + require.NoError(t, err) + + cert, err := ioutil.ReadFile("testdata/gitalycert.pem") + require.NoError(t, err) + + ok := certPool.AppendCertsFromPEM(cert) + require.True(t, ok) + + creds := credentials.NewClientTLSFromCert(certPool, "") + connOpts := []grpc.DialOption{ + grpc.WithTransportCredentials(creds), + } + + conn, err := grpc.Dial(addr, connOpts...) + require.NoError(t, err) + defer conn.Close() + + require.NoError(t, healthCheck(conn)) +} + func TestAuthFailures(t *testing.T) { defer func(oldAuth config.Auth) { config.Config.Auth = oldAuth @@ -158,7 +186,7 @@ func healthCheck(conn *grpc.ClientConn) error { } func runServer(t *testing.T) (*grpc.Server, string) { - srv := New(nil) + srv := NewInsecure(nil) serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() @@ -168,3 +196,19 @@ func runServer(t *testing.T) (*grpc.Server, string) { return srv, "unix://" + serverSocketPath } + +func runSecureServer(t *testing.T) (*grpc.Server, string) { + config.Config.TLS = config.TLS{ + CertPath: "testdata/gitalycert.pem", + KeyPath: "testdata/gitalykey.pem", + } + + srv := NewSecure(nil) + + listener, err := net.Listen("tcp", "localhost:9999") + require.NoError(t, err) + + go srv.Serve(listener) + + return srv, "localhost:9999" +} diff --git a/internal/server/server.go b/internal/server/server.go index 3d480963a4d4398f37db294c3690ed21499e138b..a29405c0d73769be95145149e754999e568a542b 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -1,11 +1,14 @@ package server import ( + "crypto/tls" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" log "github.com/sirupsen/logrus" + "gitlab.com/gitlab-org/gitaly/internal/config" "gitlab.com/gitlab-org/gitaly/internal/helper/fieldextractors" gitalylog "gitlab.com/gitlab-org/gitaly/internal/log" "gitlab.com/gitlab-org/gitaly/internal/logsanitizer" @@ -20,6 +23,7 @@ import ( grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc" "golang.org/x/net/context" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/reflection" ) @@ -58,15 +62,16 @@ func init() { grpc_logrus.ReplaceGrpcLogger(log.NewEntry(gitalylog.GrpcGo)) } -// New returns a GRPC server with all Gitaly services and interceptors set up. -func New(rubyServer *rubyserver.Server) *grpc.Server { +// createNewServer returns a GRPC server with all Gitaly services and interceptors set up. +// allows for specifying secure = true to enable tls credentials +func createNewServer(rubyServer *rubyserver.Server, secure bool) *grpc.Server { ctxTagOpts := []grpc_ctxtags.Option{ grpc_ctxtags.WithFieldExtractorForInitialReq(fieldextractors.FieldExtractor), } lh := limithandler.New(concurrencyKeyFn) - server := grpc.NewServer( + opts := []grpc.ServerOption{ grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( grpc_ctxtags.StreamServerInterceptor(ctxTagOpts...), metadatahandler.StreamInterceptor, @@ -95,7 +100,19 @@ func New(rubyServer *rubyserver.Server) *grpc.Server { // converted to errors and logged panichandler.UnaryPanicHandler, )), - ) + } + + // If tls config is specified attempt to extract tls options and use it + // as a grpc.ServerOption + if secure { + cert, err := tls.LoadX509KeyPair(config.Config.TLS.CertPath, config.Config.TLS.KeyPath) + if err != nil { + log.Fatal(err) + } + opts = append(opts, grpc.Creds(credentials.NewServerTLSFromCert(&cert))) + } + + server := grpc.NewServer(opts...) service.RegisterAll(server, rubyServer) reflection.Register(server) @@ -104,3 +121,13 @@ func New(rubyServer *rubyserver.Server) *grpc.Server { return server } + +// NewInsecure returns a GRPC server with all Gitaly services and interceptors set up. +func NewInsecure(rubyServer *rubyserver.Server) *grpc.Server { + return createNewServer(rubyServer, false) +} + +// NewSecure returns a GRPC server enabling TLS credentials +func NewSecure(rubyServer *rubyserver.Server) *grpc.Server { + return createNewServer(rubyServer, true) +} diff --git a/internal/server/testdata/gitalycert.pem b/internal/server/testdata/gitalycert.pem new file mode 100644 index 0000000000000000000000000000000000000000..8b151454896b7626b48eb325ac2e23e0edf34eac --- /dev/null +++ b/internal/server/testdata/gitalycert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +YcyGxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/internal/server/testdata/gitalykey.pem b/internal/server/testdata/gitalykey.pem new file mode 100644 index 0000000000000000000000000000000000000000..8df87e63353e442e6bf028f9a0d66e1687980760 --- /dev/null +++ b/internal/server/testdata/gitalykey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +eM9aMpgdAlLOJrfZHS3kK3968ZclB4GB +-----END PRIVATE KEY----- diff --git a/internal/service/conflicts/resolve_conflicts_test.go b/internal/service/conflicts/resolve_conflicts_test.go index 20bb2c298cc56ddd16f861e1f8887758fb77f77b..6740f2f38efc3c3c1cbeb4eca6916f8ef73cef3a 100644 --- a/internal/service/conflicts/resolve_conflicts_test.go +++ b/internal/service/conflicts/resolve_conflicts_test.go @@ -308,7 +308,7 @@ func TestFailedResolveConflictsRequestDueToValidation(t *testing.T) { } func runFullServer(t *testing.T) (*grpc.Server, string) { - server := serverPkg.New(conflicts.RubyServer) + server := serverPkg.NewInsecure(conflicts.RubyServer) serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() listener, err := net.Listen("unix", serverSocketPath) diff --git a/internal/service/operations/cherry_pick_test.go b/internal/service/operations/cherry_pick_test.go index dbdc04c27823c4e602d1d75421dc313914de3c61..bc3609c725992ae7a8bf231102aa836f5362fd86 100644 --- a/internal/service/operations/cherry_pick_test.go +++ b/internal/service/operations/cherry_pick_test.go @@ -399,7 +399,7 @@ func TestFailedUserCherryPickRequestDueToCommitError(t *testing.T) { } func runFullServer(t *testing.T) (*grpc.Server, string) { - server := serverPkg.New(operations.RubyServer) + server := serverPkg.NewInsecure(operations.RubyServer) serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() listener, err := net.Listen("unix", serverSocketPath) diff --git a/internal/service/remote/fetch_internal_remote_test.go b/internal/service/remote/fetch_internal_remote_test.go index 2d9bfc4d501be072e43e4d6fbea460b6585d708a..f30671c66c40994d28c753f96f8deb499d120a1e 100644 --- a/internal/service/remote/fetch_internal_remote_test.go +++ b/internal/service/remote/fetch_internal_remote_test.go @@ -114,7 +114,7 @@ func TestFailedFetchInternalRemoteDueToValidations(t *testing.T) { } func runFullServer(t *testing.T) (*grpc.Server, string) { - server := serverPkg.New(remote.RubyServer) + server := serverPkg.NewInsecure(remote.RubyServer) serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() listener, err := net.Listen("unix", serverSocketPath) diff --git a/internal/service/repository/fetch_test.go b/internal/service/repository/fetch_test.go index 4d1d9756d831f4e0840d234b17b0e527f106e8b4..e6b069712a039b21274bbdc520d912eea581b998 100644 --- a/internal/service/repository/fetch_test.go +++ b/internal/service/repository/fetch_test.go @@ -183,7 +183,7 @@ func newTestRepo(t *testing.T, relativePath string) (*gitalypb.Repository, strin } func runFullServer(t *testing.T) (*grpc.Server, string) { - server := serverPkg.New(repository.RubyServer) + server := serverPkg.NewInsecure(repository.RubyServer) serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() listener, err := net.Listen("unix", serverSocketPath) diff --git a/ruby/lib/gitlab/git/gitaly_remote_repository.rb b/ruby/lib/gitlab/git/gitaly_remote_repository.rb index ab0380ed741fd3d88f9717da2b4429ac56bc9b56..849172dd00f4d86000514d3fa708bc62f7abd0ed 100644 --- a/ruby/lib/gitlab/git/gitaly_remote_repository.rb +++ b/ruby/lib/gitlab/git/gitaly_remote_repository.rb @@ -31,6 +31,28 @@ module Gitlab stub.find_commit(request, request_kwargs)&.commit&.id.presence end + def certs + raise 'SSL_CERT_DIR and/or SSL_CERT_FILE environment variable must be set' unless ENV['SSL_CERT_DIR'] || ENV['SSL_CERT_FILE'] + + return @certs if @certs + + files = [] + files += Dir["#{ENV['SSL_CERT_DIR']}/*"] if ENV['SSL_CERT_DIR'] + files += [ENV['SSL_CERT_FILE']] if ENV['SSL_CERT_FILE'] + + @certs = files.map do |cert| + File.read(cert) + end.join("\n") + end + + def credentials + if URI(gitaly_client.address(storage)).scheme == 'tls' + GRPC::Core::ChannelCredentials.new certs + else + :this_channel_is_insecure + end + end + private def exists? @@ -47,14 +69,10 @@ module Gitlab def address addr = gitaly_client.address(storage) - addr = addr.sub(%r{^tcp://}, '') if URI(addr).scheme == 'tcp' + addr = addr.sub(%r{^tcp://|^tls://}, '') if %w[tcp tls].include? URI(addr).scheme addr end - def credentials - :this_channel_is_insecure - end - def token gitaly_client.token(storage).to_s end diff --git a/ruby/spec/lib/gitlab/git/remote_repository_client_spec.rb b/ruby/spec/lib/gitlab/git/remote_repository_client_spec.rb index dddb21c00f9346c431327935497a861fccc91a32..62891a2bd99bb4ae216487f3ecacea9c8f2a6ca7 100644 --- a/ruby/spec/lib/gitlab/git/remote_repository_client_spec.rb +++ b/ruby/spec/lib/gitlab/git/remote_repository_client_spec.rb @@ -5,10 +5,57 @@ describe Gitlab::Git::GitalyRemoteRepository do include IntegrationClient let(:repository) { gitlab_git_from_gitaly_with_gitlab_projects(new_mutable_test_repo) } + describe 'certs' do + let(:client) { get_client("tls://localhost:#{GitalyConfig.dynamic_port('tls')}") } + + context 'when neither SSL_CERT_FILE and SSL_CERT_DIR is set' do + it 'Raises an error' do + expect { client.certs }.to raise_error 'SSL_CERT_DIR and/or SSL_CERT_FILE environment variable must be set' + end + end + + context 'when SSL_CERT_FILE is set' do + it 'Should return the correct certificate' do + cert = File.join(File.dirname(__FILE__), "testdata/certs/gitalycert.pem") + allow(ENV).to receive(:[]).with('SSL_CERT_DIR').and_return(nil) + allow(ENV).to receive(:[]).with('SSL_CERT_FILE').and_return(cert) + certs = client.certs + expect(certs).to eq File.read(cert) + end + end + + context 'when SSL_CERT_DIR is set' do + it 'Should return concatenation of gitalycert and gitalycert2' do + cert_pool_dir = File.join(File.dirname(__FILE__), "testdata/certs") + allow(ENV).to receive(:[]).with('SSL_CERT_DIR').and_return(cert_pool_dir) + allow(ENV).to receive(:[]).with('SSL_CERT_FILE').and_return(nil) + certs = client.certs + expected_certs = [File.read(File.join(cert_pool_dir, "gitalycert2.pem")), File.read(File.join(cert_pool_dir, "gitalycert.pem"))].join "\n" + expect(certs).to eq expected_certs + end + end + + context 'when both SSL_CERT_DIR and SSL_CERT_FILE are set' do + it 'Should return all certs in SSL_CERT_DIR + SSL_CERT_FILE' do + cert_pool_dir = File.join(File.dirname(__FILE__), "testdata/certs") + cert1_file = File.join(File.dirname(__FILE__), "testdata/gitalycert.pem") + allow(ENV).to receive(:[]).with('SSL_CERT_DIR').and_return(cert_pool_dir) + allow(ENV).to receive(:[]).with('SSL_CERT_FILE').and_return(cert1_file) + expected_certs_paths = [File.join(cert_pool_dir, "gitalycert2.pem"), File.join(cert_pool_dir, "gitalycert.pem"), cert1_file] + + expected_certs = expected_certs_paths.map do |cert| + File.read cert + end.join("\n") + certs = client.certs + expect(certs).to eq expected_certs + end + end + end + describe 'Connectivity' do context 'tcp' do let(:client) do - get_client("tcp://localhost:#{GitalyConfig.dynamic_port}") + get_client("tcp://localhost:#{GitalyConfig.dynamic_port('tcp')}") end it 'Should connect over tcp' do @@ -23,5 +70,17 @@ describe Gitlab::Git::GitalyRemoteRepository do expect(client).not_to be_empty end end + + context 'tls' do + let(:client) { get_client("tls://localhost:#{GitalyConfig.dynamic_port('tls')}") } + + it 'Should connect over tls' do + cert = File.join(File.dirname(__FILE__), "testdata/certs/gitalycert.pem") + allow(ENV).to receive(:[]).with('SSL_CERT_DIR').and_return(nil) + allow(ENV).to receive(:[]).with('SSL_CERT_FILE').and_return(cert) + + expect(client).not_to be_empty + end + end end end diff --git a/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert.pem b/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert.pem new file mode 100755 index 0000000000000000000000000000000000000000..8b151454896b7626b48eb325ac2e23e0edf34eac --- /dev/null +++ b/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +YcyGxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert2.pem b/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert2.pem new file mode 100755 index 0000000000000000000000000000000000000000..4708f8ec36d79159d801e7221bf3f9d0f97cc21d --- /dev/null +++ b/ruby/spec/lib/gitlab/git/testdata/certs/gitalycert2.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +Ykkjkxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/ruby/spec/lib/gitlab/git/testdata/gitalycert.pem b/ruby/spec/lib/gitlab/git/testdata/gitalycert.pem new file mode 100755 index 0000000000000000000000000000000000000000..8b151454896b7626b48eb325ac2e23e0edf34eac --- /dev/null +++ b/ruby/spec/lib/gitlab/git/testdata/gitalycert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +YcyGxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/ruby/spec/support/helpers/certs/gitalycert.pem b/ruby/spec/support/helpers/certs/gitalycert.pem new file mode 100755 index 0000000000000000000000000000000000000000..8b151454896b7626b48eb325ac2e23e0edf34eac --- /dev/null +++ b/ruby/spec/support/helpers/certs/gitalycert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCAyACCQDpPfNtveVc8TANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJV +UzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzAN +BgNVBAsMBmdpdGFseTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE4MTEwMjA5MDIx +MloYDzIxMTgxMDA5MDkwMjEyWjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMx +CzAJBgNVBAcMAlVTMQ8wDQYDVQQKDAZHaXRMYWIxDzANBgNVBAsMBmdpdGFseTES +MBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEApJXJOWpUkV32v8gRXLWn6TEsQmy2WeilQXg96V6VOQjGZAGMEJLEjH9WHBNe +Zi4V+W+j1FB8vWTNRGTcOcpSEmDFuewoBJVA8dFtNF4jj7QQymmnKeDuOW4fWLeU +YcyGxyjlpkm2+DUg5CavT4bMZILqbsAavxJ8SKCdJpMtW3sxklnGuTHcAckHldab +9ZxH/qYqLxc5Ek2BK4OibBxA84h1RUsqe2EdzZUOoet3xpwG3Vr8bGPqR7Psghs6 +TDdWU8hYYHlReCWezgZHiYDoRqY9HCZrHSpUZ1lbRo++2j4bvdFHOAUm4BEQ6fFc +sgtW+xkNK8bxj9XTcpuDrEVscv3fyBlCMSvD+HpNbr2k1oZSOFhxISIwBLKWQBjq +5muvMRbmrG5RgWqMWjXb+g0UmlyMa2YWAWsBgSuUSjJePgbUZWHuxp/dM8CQ4lHJ +ADvfSI9ysJQM/trqjRu5BRhxiKWR72QSi1qpDPT0nKWlzQ58zs3RSuOJbWm8oOqr +XL9G/XmvgzK1qwToI/WmXBeaqmfpkagYZm+TJW0GVnDqTC+EoXdFKW7aWIjlcb4p +tYoiRA/2jjq5OqeV6iKnxz7mEJQR1xDebm6+AWgFy4zyB/QvzanaUTvNiLhyBy6Q +YwXJHkNh+KrVszBlXxkARrGesXgqOznmDeErkOKDjxzQv+cCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAk83b9wY9iwRrx5Yep3DA3xZkVu3GJcKf0tTL8apP1MzVBSUK +5tkvW2Z4D41jpZWgJDRF8/nT2lvVwvd5xQ8/oTUerFeG/ZZ+AiBagkBKl8piPHqD +cefAO8N2SKoYHV4xBeoVU6InUuJ7xu7BLF6tY3xKvx0XsjGC7B621xmq+E56dPZg +sQwekkxODbUw4NekqYFY21BT4xiWVrTRLIGY9AfV9Ry4gqQTxda7yst4ykWh1a9e +O+426uz3jshzpQTjZwk8kCZquJKa8Qzqfdlevns0FQDP5jck4BH/YkMNsa/g9XCd +ZHSB7gqAfNoNTB1rqNKIfPUF4mTu/RWMVwxb8f6h0TfywHZ4q/4R3Zfu3jUyeVVY +ziJu2CJpcoR9SESKFbN4WFzk91nIhf2pCGo/qNO5f+n5ZPnS2jrrWL5h64e1rz2h +rVKIYLfeM2M8lVzSL1V0aJ+POcruTRsmlrFT5f7na/5YFt5N+5Z5fzixCLr1MK2w +4gFw+KhN7CAhKGzHq3NBdWpRFFMR53hyeYsb1vvwFu07JTRh+NbaePk/sk07WtCo +u2w6pD7xlayTAWcR9WRBv7c3lDejN80U8DONb8fLwtI5oIrkSuwOqvmlDOeFpKiT +MwTB6oC81Ar39P0R53247w7u9plhPUrmDn/A5KphW633UvgbkH6VmB4Isiw= +-----END CERTIFICATE----- diff --git a/ruby/spec/support/helpers/certs/gitalykey.pem b/ruby/spec/support/helpers/certs/gitalykey.pem new file mode 100644 index 0000000000000000000000000000000000000000..8df87e63353e442e6bf028f9a0d66e1687980760 --- /dev/null +++ b/ruby/spec/support/helpers/certs/gitalykey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCklck5alSRXfa/ +yBFctafpMSxCbLZZ6KVBeD3pXpU5CMZkAYwQksSMf1YcE15mLhX5b6PUUHy9ZM1E +ZNw5ylISYMW57CgElUDx0W00XiOPtBDKaacp4O45bh9Yt5RhzIbHKOWmSbb4NSDk +Jq9PhsxkgupuwBq/EnxIoJ0mky1bezGSWca5MdwByQeV1pv1nEf+piovFzkSTYEr +g6JsHEDziHVFSyp7YR3NlQ6h63fGnAbdWvxsY+pHs+yCGzpMN1ZTyFhgeVF4JZ7O +BkeJgOhGpj0cJmsdKlRnWVtGj77aPhu90Uc4BSbgERDp8VyyC1b7GQ0rxvGP1dNy +m4OsRWxy/d/IGUIxK8P4ek1uvaTWhlI4WHEhIjAEspZAGOrma68xFuasblGBaoxa +Ndv6DRSaXIxrZhYBawGBK5RKMl4+BtRlYe7Gn90zwJDiUckAO99Ij3KwlAz+2uqN +G7kFGHGIpZHvZBKLWqkM9PScpaXNDnzOzdFK44ltabyg6qtcv0b9ea+DMrWrBOgj +9aZcF5qqZ+mRqBhmb5MlbQZWcOpML4Shd0UpbtpYiOVxvim1iiJED/aOOrk6p5Xq +IqfHPuYQlBHXEN5ubr4BaAXLjPIH9C/NqdpRO82IuHIHLpBjBckeQ2H4qtWzMGVf +GQBGsZ6xeCo7OeYN4SuQ4oOPHNC/5wIDAQABAoICAHjlPeZa4LvXFcVSJM7A8RIt ++KDiUiBA8ALjXDbsLxiyBWi4ajZSWOYLMyl0YMcV2zZadzEh3j8QqGcw30PkBd1S +EGu9uLeFGyuF9n2dGOoaDqtgaFYuz06IQaZdUzVzkx0AQZCgXTJ9dCei8uurzL+Y +GrQ3kG4CGiEPOeB4A71LBOLH511p7n2xOU0rU2xa29eGHz5wBJAZNmTMUKaxKlS5 +S8sWp6HxeH7mmtT9rgHJ4pD+oKTNz+3TkEsRzQTnMRZh9+kFtH5YxAn6OtoaQoSC +4CipX80QpuczkASI2lxdeus3quTPg/rbDl2J2dk+0ymnATHC9PX+z09ERLhqVnoD +QBY+vIw8Opj7GB/viWm/IiF0wseM+qEgr+f1qgl8pRe4N+EeD2OCnB++kslOhol+ +50KJbMJ/bfHo/3NKCqAHoKd/gk4HAiqmEKHRgSaXXjvE6bBRoFeL20zFitzCWm8z +H3CexwDRY0qJqy80Qahg+NQX58MkYskOA42fFMzuvUxfYIu/mpTTDvRK5jxsDffe +cPU2BTcbxi5hCJjo7ertid5JGp51jr6XvViuDYf77hhw8Cm5KdeavHcF1XgksRa3 +SHTtDv/Um1RvOqMzINy1Z5mFdBN8TdzEA+9gPCm+pqpD0FTDiu/IkggYeszk0syf +AIhoEJI8PkBKqQj0DxoBAoIBAQDZ96DL+fzwXN13aqhvYNTfGxZ3RCP40KCuCSrQ +gjcGcGavFOR21Y5CHaFmIFNmrtXTj3P950N+a8/KNAmm9zFx6060HEHyR6rN5b0h +BMMlp7ezyPY+VCWJWCEi3TD+4LseAynyP05rWdm2+nsGBxaXWB8yAq0CwuyYTQdZ +IZHGKeGI9irv+5mIe7bVRCVEug22u6gHmOLERXCqO70Mzi/c/UFxjGmF0LR4d7TY +VIQ5r/PPvXJzf72PVIPwJQzRsaOXnZvD1UzSahyaB3fABB6I1y6OfXyU8BukwBQ5 +J0qVRFpzMc46PFULQC5KTUIzPcnrW73UWEu5XGiAooN5SysnAoIBAQDBTaGC/5xO +755EdZggpx+05LlmoW0ijeDnuRcKPlwap4dPFUSQS2EOWxjmm4K8sNAOdiQt7Jwf +gX/S6jdY79V0rkyktWk1uCfiwu1c/rvyLdl2Jg1RW6HByL7MTBuASfuCgJsfzhev +yu+HzPJMQNFhgQTcLL9LYHp5moGKCbJzIp+FXOeFokjjlynrrmPoHV0A8To6s7q2 +yH5qu9OaOu75kWqDul5b9cXO+isxUBZbEjUy7OEa3Zezuhq8XgZVE5t2QgJOnDI/ +NNp5d16N7GcDpaEZzSNag95F0+wsFIgT29LL2zSF6h3+VjeqKTxwbRtFsMboN9TZ +QHIgBB+2ib1BAoIBAQDC31r6ovFacJxsZIZctcT8BzrJvLkwfk356yZFLvZFIn8b +r2EnQX0jbVxcczA9kLiJoirA6V91iqxHCslKZpzlTcyayNzI4Pw7g1fZSmmyo8Vg +zp4hUZgRuCJACmQArCl/BrMc6y6QWc+FgWI2HGY9P0L8slm+K0neTJfyP0oWUmFa +00PGNTqqRHlNKNTtIi6aniH3UOAFPFQjTq+R4FH4kNBO1YuOYO7I+bVM6BsjfEVO +CQFnc+ClYZloPae9XsV1Cys1JeG+CbKyn1SX7tbh3wi3ykd03UrJvBUYmCFdXLRF +Y1UOydv66BG6ymISb/60FtycGajx+0VPJHzJF8RnAoIBAQCVVyyY0HIqaeWUbmWB +lJxiXPL/32c5cvN3EwBB4bu2vAdFieDWueXZ+Xdbcnmm3dNf2NZKxKo5jQr8IAdy +ppf69U4xUhZeclAeWQqY9hSuHc4MAYn4eRqXZEhD/eihTIcLY+B0yfxyzA4SlLv9 +PXaGJe9jSw7fZUI6AKxjwOolGXK0zfnwvFgjvP2eH7T/9u+LctLR11lBLdS9ES+B +0FYgacAo1SthUJfqOEx2ZLFg2shO98NRxjEVoYpWTS4HPIa27nhp0zLesi63+QkM +DL/piWTVUi8mFwr6V6f2xkX7UbGh3VDOxPk3LdUDmaggE6smRFTnw3ql/awuIAGA +PRoBAoIBAQCwIkbP/Py8qXkrUil/ZW2+7yPXy4DeOkduLBrLBXH5fxAPUoyOywjl +CFOVcHNuioRZnN22M64VzlCgRhY4gD+ypyeFmVR4fHBWZuQObwt6jkaGXxvcGl+U +cDrMYt1xjJbjEdvX4+VjkLwJzIAzBG09agk3eLwcVAH8w5uteyKNdi0Kg9mClFJm +LRJNjI6fp5KfVitMEthx9WEe5Zu9phBLCtqYNYQoH+VY3yp8aD9NB0X5sgHYKCaK +jgQUpEnGU9zSnKeK8MglhWson3a6NEjPufsAjHgGHbTAfGEXLkiHZee3gAB2BJdk +eM9aMpgdAlLOJrfZHS3kK3968ZclB4GB +-----END PRIVATE KEY----- diff --git a/ruby/spec/support/helpers/integration_helper.rb b/ruby/spec/support/helpers/integration_helper.rb index 9c717261f94e4276ef50e15821845982d492cdb7..6e6631ba9a6cdb7440b9bf5681f365ee492cd2b7 100644 --- a/ruby/spec/support/helpers/integration_helper.rb +++ b/ruby/spec/support/helpers/integration_helper.rb @@ -6,14 +6,28 @@ require 'spec_helper' SOCKET_PATH = 'gitaly.socket'.freeze module GitalyConfig - def self.dynamic_port - @dynamic_port ||= begin - sock = Socket.new(:INET, :STREAM) - sock.bind(Addrinfo.tcp('127.0.0.1', 0)) - sock.local_address.ip_port - ensure - sock.close - end + def self.set_dynamic_ports + tcp_sock = Socket.new(:INET, :STREAM) + tls_sock = Socket.new(:INET, :STREAM) + tcp_sock.bind(Addrinfo.tcp('127.0.0.1', 0)) + tls_sock.bind(Addrinfo.tcp('127.0.0.1', 0)) + + @dynamic_tcp_port = tcp_sock.local_address.ip_port + @dynamic_tls_port = tls_sock.local_address.ip_port + ensure + tcp_sock.close + tls_sock.close + end + + def self.dynamic_port(type) + set_dynamic_ports unless @dynamic_tcp_port && @dynamic_tls_port + + case type + when 'tcp' + @dynamic_tcp_port + when 'tls' + @dynamic_tls_port + end end end @@ -23,8 +37,8 @@ module IntegrationClient addr = case type when 'unix' "unix:#{File.join(TMP_DIR_NAME, SOCKET_PATH)}" - when 'tcp' - "tcp://localhost:#{GitalyConfig.dynamic_port}" + when 'tcp', 'tls' + "#{type}://localhost:#{GitalyConfig.dynamic_port(type)}" end klass.new(addr, creds) end @@ -54,11 +68,18 @@ def start_gitaly build_dir = File.expand_path(File.join(GITALY_RUBY_DIR, '../_build')) GitlabShellHelper.setup_gitlab_shell + cert_path = File.join(File.dirname(__FILE__), "/certs") + config_toml = <<~CONFIG socket_path = "#{SOCKET_PATH}" - listen_addr = "localhost:#{GitalyConfig.dynamic_port}" + listen_addr = "localhost:#{GitalyConfig.dynamic_port('tcp')}" + tls_listen_addr = "localhost:#{GitalyConfig.dynamic_port('tls')}" bin_dir = "#{build_dir}/bin" + [tls] + certificate_path = "#{cert_path}/gitalycert.pem" + key_path = "#{cert_path}/gitalykey.pem" + [gitlab-shell] dir = "#{GITLAB_SHELL_DIR}"