5b913c45b9
* wip initial transport security * wip: transport security (add tests / refactor) * wip tests * refactoring - still wip * refactor, improve tests * wip tls testing * fix typo * wip testing * wip testing * wip * tls_test passing * code-style improvemente / refactor; service and tls tests passing! * code-style auto-format * add TestNewServer_LoadTLS * refactor; test improvements * refactor * add client cert * port changes * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * files created * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * wip * add separate `Process` tests for bolt and redis-backed overlay * more testing * fix gitignore * fix linter error * goimports goimports GOIMPORTS GoImPortS!!!! * wip * fix port madness * forgot to add * add `mux` as handler and shorten context timeouts * gofreakingimports * fix comments * refactor test & add logger/monkit registry * debugging travis * add comment * Set redisAddress to empty string for bolt-test * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * Merge branch 'tls' into tls-upstream * tls: add client cert refactor refactor; test improvements add TestNewServer_LoadTLS code-style auto-format code-style improvemente / refactor; service and tls tests passing! tls_test passing wip wip testing wip testing fix typo wip tls testing refactor, improve tests refactoring - still wip wip tests wip: transport security (add tests / refactor) wip initial transport security * fixing linter things * wip * remove bkad dependencie from tests * wip * wip * wip * wip * wip * updated coyle/kademlia * wip * cleanup * ports * overlay upgraded * linter fixes * piecestore kademlia newID * Merge branch 'master' into tls-upstream * master: Add error to the return values of Ranger.Range method (#90) udp-forwarding: demo week work! (#84) * Merge branch 'kad-tests' into tls-upstream * kad-tests: piecestore kademlia newID linter fixes overlay upgraded ports cleanup wip updated coyle/kademlia wip wip wip wip wip remove bkad dependencie from tests wip wip files created port changes * wip * finish merging service tests * add test for different client/server certs * wip * Merge branch 'master' into tls-upstream * master: Add context to Ranger.Range method (#99) Coyle/kad client (#91) * wip * wip; refactoring/cleanup * wip * Merge branch 'master' into tls * master: Bolt backed overlay cache (#94) internal/test: switch errors to error classes (#96) * wip - test passing * cleanup * remove port.go * cleanup * Merge branch 'master' into tls * master: hardcode version (#111) Coyle/docker fix (#109) pkg/kademlia tests and restructuring (#97) Use continue instead of return in table tests (#106) prepend storjlabs to docker tag (#108) Automatically build, tag and push docker images on merge to master (#103) * more belated merging * more belated merging * more belated merging * add copyrights * cleanup * goimports * refactoring * wip * wip * implement `TLSFileOptions#loadTLS`, refactoring: `peertls.TestNewClient_LoadTLS` is the failing holdout; Still trying to figure out why I'm getting ECDSA verification is failing. * not sure if actually working: Tests are now passing (no more "ECDSA verification failed"); however, `len(*tls.Certificates.Certificate) == 1` which I don't think should be the case if the root and leaf are being created correctly. * Experimenting/bugfixing?: I think leaf certs should be properly signed by the parent now but not entirely certain. It's also unclear to me why in `VerifyPeerCertificate`, `len(rawCerts) == 1` when the certs should contain both the root and leaf afaik. * Properly write/read certificate chain (root/leaf): I think I'm now properly reading and writing the root and leaf certificate chain such that they're both being received by `VerifyPeerCertificate`. The next step is to parse the certificates with `x509.ParseCertificate` (or similar) and verify that the public keys and signatures match. * Add tls certificate chain signature veification (spike): + `VerifyPeerCertificate` verifies signatures of certificates using the key of it's parent if there is one; otherwise, it verifies the certificate is self-signed + TODO: refactor + TODO: test * refactoring `VerifyPeerCertificate` * cleanup * refactor * Merge branch 'master' into tls * master: Remove some structural folders we don't seem to be using. (#125) license code with agplv3 (#126) Update .clabot (#124) added team memebers (#123) clabot file added (#121) ECClient (#110) docker image issue fixed (#118) Piecestore Farmer CLI (#92) Define Path type (#101) adds netstate pagination (#95) Transport Client (#89) Implement psclient interface (#107) pkg/process: start replacing pkg/process with cobra helpers (#98) protos/netstate: remove stuff we're not using (#100) adding coveralls / code coverage (#112) * responding to review feedback / cleanup / add copywrite headers * suggestions * realitive * Merge pull request #1 from coyle/coyle/tls suggestions * remove unnecessary `_`s * Merge branch 'tls' of github.com:bryanchriswhite/storj into tls * 'tls' of github.com:bryanchriswhite/storj: realitive suggestions * Responding to review feedback: + refactor `VerifyPeerCertificate` * remove tls expiration * remove "hosts" and "clien option" from tls options * goimports * linter fixes
227 lines
6.8 KiB
Go
227 lines
6.8 KiB
Go
// Copyright (C) 2018 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package overlay
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/spf13/cobra"
|
|
"go.uber.org/zap"
|
|
"google.golang.org/grpc"
|
|
"gopkg.in/spacemonkeygo/monkit.v2"
|
|
|
|
"storj.io/storj/pkg/kademlia"
|
|
"storj.io/storj/pkg/peertls"
|
|
"storj.io/storj/pkg/process"
|
|
proto "storj.io/storj/protos/overlay"
|
|
)
|
|
|
|
var (
|
|
redisAddress, redisPassword, httpPort, bootstrapIP, bootstrapPort, localPort, boltdbPath string
|
|
db int
|
|
srvPort uint
|
|
options peertls.TLSFileOptions
|
|
)
|
|
|
|
func init() {
|
|
flag.StringVar(&httpPort, "httpPort", "", "The port for the health endpoint")
|
|
flag.StringVar(&redisAddress, "redisAddress", "", "The <IP:PORT> string to use for connection to a redis cache")
|
|
flag.StringVar(&redisPassword, "redisPassword", "", "The password used for authentication to a secured redis instance")
|
|
flag.StringVar(&boltdbPath, "boltdbPath", "", "The path to the boltdb file that should be loaded or created")
|
|
flag.IntVar(&db, "db", 0, "The network cache database")
|
|
flag.UintVar(&srvPort, "srvPort", 8080, "Port to listen on")
|
|
flag.StringVar(&bootstrapIP, "bootstrapIP", "", "Optional IP to bootstrap node against")
|
|
flag.StringVar(&bootstrapPort, "bootstrapPort", "", "Optional port of node to bootstrap against")
|
|
flag.StringVar(&localPort, "localPort", "8081", "Specify a different port to listen on locally")
|
|
flag.StringVar(&options.RootCertRelPath, "tlsCertBasePath", "", "The base path for TLS certificates")
|
|
flag.StringVar(&options.RootKeyRelPath, "tlsKeyBasePath", "", "The base path for TLS keys")
|
|
flag.BoolVar(&options.Create, "tlsCreate", false, "If true, generate a new TLS cert/key files")
|
|
flag.BoolVar(&options.Overwrite, "tlsOverwrite", false, "If true, overwrite existing TLS cert/key files")
|
|
}
|
|
|
|
// NewServer creates a new Overlay Service Server
|
|
func NewServer(k *kademlia.Kademlia, cache *Cache, l *zap.Logger, m *monkit.Registry) *grpc.Server {
|
|
grpcServer := grpc.NewServer()
|
|
proto.RegisterOverlayServer(grpcServer, &Server{
|
|
dht: k,
|
|
cache: cache,
|
|
logger: l,
|
|
metrics: m,
|
|
})
|
|
|
|
return grpcServer
|
|
}
|
|
|
|
// NewClient connects to grpc server at the provided address with the provided options
|
|
// returns a new instance of an overlay Client
|
|
func NewClient(serverAddr *string, opts ...grpc.DialOption) (proto.OverlayClient, error) {
|
|
conn, err := grpc.Dial(*serverAddr, opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return proto.NewOverlayClient(conn), nil
|
|
}
|
|
|
|
// NewTLSServer returns a newly initialized gRPC overlay server, configured with TLS
|
|
func NewTLSServer(k *kademlia.Kademlia, cache *Cache, l *zap.Logger, m *monkit.Registry, fopts peertls.TLSFileOptions) (_ *grpc.Server, _ error) {
|
|
t, err := peertls.NewTLSFileOptions(
|
|
fopts.RootCertRelPath,
|
|
fopts.RootKeyRelPath,
|
|
fopts.Create,
|
|
fopts.Overwrite,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
grpcServer := grpc.NewServer(t.ServerOption())
|
|
proto.RegisterOverlayServer(grpcServer, &Server{
|
|
dht: k,
|
|
cache: cache,
|
|
logger: l,
|
|
metrics: m,
|
|
})
|
|
|
|
return grpcServer, nil
|
|
}
|
|
|
|
// NewTLSClient connects to grpc server at the provided address with the provided options plus TLS option(s)
|
|
// returns a new instance of an overlay Client
|
|
func NewTLSClient(serverAddr *string, fopts peertls.TLSFileOptions, opts ...grpc.DialOption) (proto.OverlayClient, error) {
|
|
t, err := peertls.NewTLSFileOptions(
|
|
fopts.RootCertRelPath,
|
|
fopts.RootCertRelPath,
|
|
fopts.Create,
|
|
fopts.Overwrite,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
opts = append(opts, t.DialOption())
|
|
conn, err := grpc.Dial(*serverAddr, opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return proto.NewOverlayClient(conn), nil
|
|
}
|
|
|
|
// Service contains all methods needed to implement the process.Service interface
|
|
type Service struct {
|
|
logger *zap.Logger
|
|
metrics *monkit.Registry
|
|
}
|
|
|
|
// Process is the main function that executes the service
|
|
func (s *Service) Process(ctx context.Context, _ *cobra.Command, _ []string) (
|
|
err error) {
|
|
// TODO
|
|
// 1. Boostrap a node on the network
|
|
// 2. Start up the overlay gRPC service
|
|
// 3. Connect to Redis
|
|
// 4. Boostrap Redis Cache
|
|
|
|
// TODO(coyle): Should add the ability to pass a configuration to change the bootstrap node
|
|
in, err := kademlia.GetIntroNode("", bootstrapIP, bootstrapPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
id, err := kademlia.NewID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
kad, err := kademlia.NewKademlia(id, []proto.Node{*in}, "0.0.0.0", localPort)
|
|
if err != nil {
|
|
s.logger.Error("Failed to instantiate new Kademlia", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if err := kad.ListenAndServe(); err != nil {
|
|
s.logger.Error("Failed to ListenAndServe on new Kademlia", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if err := kad.Bootstrap(ctx); err != nil {
|
|
s.logger.Error("Failed to Bootstrap on new Kademlia", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// bootstrap cache
|
|
var cache *Cache
|
|
if redisAddress != "" {
|
|
cache, err = NewRedisOverlayCache(redisAddress, redisPassword, db, kad)
|
|
if err != nil {
|
|
s.logger.Error("Failed to create a new redis overlay client", zap.Error(err))
|
|
return err
|
|
}
|
|
} else if boltdbPath != "" {
|
|
cache, err = NewBoltOverlayCache(boltdbPath, kad)
|
|
if err != nil {
|
|
s.logger.Error("Failed to create a new boltdb overlay client", zap.Error(err))
|
|
return err
|
|
}
|
|
} else {
|
|
return process.ErrUsage.New("You must specify one of `--boltdbPath` or `--redisAddress`")
|
|
}
|
|
|
|
if boltdbPath != "" {
|
|
|
|
}
|
|
|
|
if err := cache.Bootstrap(ctx); err != nil {
|
|
s.logger.Error("Failed to boostrap cache", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// send off cache refreshes concurrently
|
|
go cache.Refresh(ctx)
|
|
|
|
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", srvPort))
|
|
if err != nil {
|
|
s.logger.Error("Failed to initialize TCP connection", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
grpcServer := NewServer(kad, cache, s.logger, s.metrics)
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "OK") })
|
|
go func() { http.ListenAndServe(fmt.Sprintf(":%s", httpPort), mux) }()
|
|
go cache.Walk(ctx)
|
|
|
|
// If the passed context times out or is cancelled, shutdown the gRPC server
|
|
go func() {
|
|
if _, ok := <-ctx.Done(); !ok {
|
|
grpcServer.GracefulStop()
|
|
}
|
|
}()
|
|
|
|
// If `grpcServer.Serve(...)` returns an error, shutdown/cleanup the gRPC server
|
|
defer grpcServer.GracefulStop()
|
|
return grpcServer.Serve(lis)
|
|
}
|
|
|
|
// SetLogger adds the initialized logger to the Service
|
|
func (s *Service) SetLogger(l *zap.Logger) error {
|
|
s.logger = l
|
|
return nil
|
|
}
|
|
|
|
// SetMetricHandler adds the initialized metric handler to the Service
|
|
func (s *Service) SetMetricHandler(m *monkit.Registry) error {
|
|
s.metrics = m
|
|
return nil
|
|
}
|
|
|
|
// InstanceID implements Service.InstanceID
|
|
func (s *Service) InstanceID() string { return "" }
|