diff --git a/Makefile b/Makefile index 0e715ef16..93312024e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ GOTOOLS = \ github.com/golang/dep/cmd/dep \ github.com/gogo/protobuf/protoc-gen-gogo \ - github.com/gogo/protobuf/gogoproto + github.com/gogo/protobuf/gogoproto \ + github.com/square/certstrap # github.com/alecthomas/gometalinter.v2 \ GOTOOLS_CHECK = dep gometalinter.v2 protoc protoc-gen-gogo @@ -66,8 +67,21 @@ get_vendor_deps: ######################################## ### Testing -test: +gen_certs: clean_certs + ## Generating certificates for TLS testing... + certstrap init --common-name "tendermint.com" --passphrase "" + certstrap request-cert -ip "::" --passphrase "" + certstrap sign "::" --CA "tendermint.com" --passphrase "" + mv out/{::.crt,::.key} remotedb + +clean_certs: + ## Cleaning TLS testing certificates... + rm -rf out + rm -f remotedb/{::.crt,::.key} + +test: gen_certs go test -tags gcc $(shell go list ./... | grep -v vendor) + make clean_certs test100: @for i in {1..100}; do make test; done @@ -118,7 +132,7 @@ metalinter_all: # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html -.PHONY: check protoc build check_tools get_tools get_protoc update_tools get_vendor_deps test fmt metalinter metalinter_all +.PHONY: check protoc build check_tools get_tools get_protoc update_tools get_vendor_deps test fmt metalinter metalinter_all gen_certs clean_certs grpc_dbserver: protoc -I proto/ proto/defs.proto --go_out=plugins=grpc:proto diff --git a/grpcdb/client.go b/grpcdb/client.go index a09720abc..07fd461ec 100644 --- a/grpcdb/client.go +++ b/grpcdb/client.go @@ -2,6 +2,7 @@ package grpcdb import ( "google.golang.org/grpc" + "google.golang.org/grpc/credentials" protodb "github.com/tendermint/tmlibs/proto" ) @@ -16,12 +17,12 @@ const ( // NewClient creates a gRPC client connected to the bound gRPC server at serverAddr. // Use kind to set the level of security to either Secure or Insecure. -func NewClient(serverAddr string, kind Security) (protodb.DBClient, error) { - var opts []grpc.DialOption - if kind == Insecure { - opts = append(opts, grpc.WithInsecure()) +func NewClient(serverAddr string, serverCert string) (protodb.DBClient, error) { + creds, err := credentials.NewClientTLSFromFile(serverCert, "") + if err != nil { + return nil, err } - cc, err := grpc.Dial(serverAddr, opts...) + cc, err := grpc.Dial(serverAddr, grpc.WithTransportCredentials(creds)) if err != nil { return nil, err } diff --git a/grpcdb/doc.go b/grpcdb/doc.go index a54cab207..c92de82d3 100644 --- a/grpcdb/doc.go +++ b/grpcdb/doc.go @@ -21,8 +21,10 @@ should use it, for functionality such as: or addr := ":8998" + cert := "server.crt" + key := "server.key" go func() { - if err := grpcdb.ListenAndServe(addr); err != nil { + if err := grpcdb.ListenAndServe(addr, cert, key); err != nil { log.Fatalf("BindServer: %v", err) } }() diff --git a/grpcdb/example_test.go b/grpcdb/example_test.go index cbe1abf92..5a9c6eed9 100644 --- a/grpcdb/example_test.go +++ b/grpcdb/example_test.go @@ -11,13 +11,15 @@ import ( func Example() { addr := ":8998" + cert := "server.crt" + key := "server.key" go func() { - if err := grpcdb.ListenAndServe(addr); err != nil { + if err := grpcdb.ListenAndServe(addr, cert, key); err != nil { log.Fatalf("BindServer: %v", err) } }() - client, err := grpcdb.NewClient(addr, grpcdb.Insecure) + client, err := grpcdb.NewClient(addr, cert) if err != nil { log.Fatalf("Failed to create grpcDB client: %v", err) } diff --git a/grpcdb/server.go b/grpcdb/server.go index 1e8495300..d8dc1581f 100644 --- a/grpcdb/server.go +++ b/grpcdb/server.go @@ -7,6 +7,7 @@ import ( "time" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "github.com/tendermint/tmlibs/db" protodb "github.com/tendermint/tmlibs/proto" @@ -15,19 +16,27 @@ import ( // ListenAndServe is a blocking function that sets up a gRPC based // server at the address supplied, with the gRPC options passed in. // Normally in usage, invoke it in a goroutine like you would for http.ListenAndServe. -func ListenAndServe(addr string, opts ...grpc.ServerOption) error { +func ListenAndServe(addr string, cert string, key string, opts ...grpc.ServerOption) error { ln, err := net.Listen("tcp", addr) if err != nil { return err } - srv := NewServer(opts...) + srv, err := NewServer(cert, key, opts...) + if err != nil { + return err + } return srv.Serve(ln) } -func NewServer(opts ...grpc.ServerOption) *grpc.Server { +func NewServer(cert string, key string, opts ...grpc.ServerOption) (*grpc.Server, error) { + creds, err := credentials.NewServerTLSFromFile(cert, key) + if err != nil { + return nil, err + } + opts = append(opts, grpc.Creds(creds)) srv := grpc.NewServer(opts...) protodb.RegisterDBServer(srv, new(server)) - return srv + return srv, nil } type server struct { diff --git a/remotedb/remotedb.go b/remotedb/remotedb.go index a110e816c..b80cd3fdb 100644 --- a/remotedb/remotedb.go +++ b/remotedb/remotedb.go @@ -14,12 +14,8 @@ type RemoteDB struct { dc protodb.DBClient } -func NewSecure(serverAddr string) (*RemoteDB, error) { - return newRemoteDB(grpcdb.NewClient(serverAddr, grpcdb.Secure)) -} - -func NewInsecure(serverAddr string) (*RemoteDB, error) { - return newRemoteDB(grpcdb.NewClient(serverAddr, grpcdb.Insecure)) +func NewRemoteDB(serverAddr string, serverKey string) (*RemoteDB, error) { + return newRemoteDB(grpcdb.NewClient(serverAddr, serverKey)) } func newRemoteDB(gdc protodb.DBClient, err error) (*RemoteDB, error) { diff --git a/remotedb/remotedb_test.go b/remotedb/remotedb_test.go index 37ce0c59a..a5b77cf5a 100644 --- a/remotedb/remotedb_test.go +++ b/remotedb/remotedb_test.go @@ -11,9 +11,12 @@ import ( ) func TestRemoteDB(t *testing.T) { + cert := "::.crt" + key := "::.key" ln, err := net.Listen("tcp", "0.0.0.0:0") require.Nil(t, err, "expecting a port to have been assigned on which we can listen") - srv := grpcdb.NewServer() + srv, err := grpcdb.NewServer(cert, key) + require.Nil(t, err) defer srv.Stop() go func() { if err := srv.Serve(ln); err != nil { @@ -21,7 +24,7 @@ func TestRemoteDB(t *testing.T) { } }() - client, err := remotedb.NewInsecure(ln.Addr().String()) + client, err := remotedb.NewRemoteDB(ln.Addr().String(), cert) require.Nil(t, err, "expecting a successful client creation") require.Nil(t, client.InitRemote(&remotedb.Init{Name: "test-remote-db", Type: "leveldb"}))