Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QSP-4 Use Self-Signed, Secure gRPC Connection by Default #6428

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions beacon-chain/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ var appFlags = []cli.Flag{
cmd.TracingEndpointFlag,
cmd.TraceSampleFractionFlag,
cmd.MonitoringHostFlag,
cmd.InsecureGRPCFlag,
flags.MonitoringPortFlag,
cmd.DisableMonitoringFlag,
cmd.ClearDB,
Expand Down
4 changes: 4 additions & 0 deletions beacon-chain/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,20 +562,24 @@ func (b *BeaconNode) registerRPCService() error {
port := b.cliCtx.String(flags.RPCPort.Name)
cert := b.cliCtx.String(flags.CertFlag.Name)
key := b.cliCtx.String(flags.KeyFlag.Name)
datadir := b.cliCtx.String(cmd.DataDirFlag.Name)
slasherCert := b.cliCtx.String(flags.SlasherCertFlag.Name)
slasherProvider := b.cliCtx.String(flags.SlasherProviderFlag.Name)
mockEth1DataVotes := b.cliCtx.Bool(flags.InteropMockEth1DataVotesFlag.Name)
enableDebugRPCEndpoints := b.cliCtx.Bool(flags.EnableDebugRPCEndpoints.Name)
insecureGRPC := b.cliCtx.Bool(cmd.InsecureGRPCFlag.Name)
p2pService := b.fetchP2P()
rpcService := rpc.NewService(b.ctx, &rpc.Config{
Host: host,
Port: port,
CertFlag: cert,
KeyFlag: key,
DataDir: datadir,
BeaconDB: b.db,
Broadcaster: p2pService,
PeersFetcher: p2pService,
PeerManager: p2pService,
InsecureGRPC: insecureGRPC,
HeadFetcher: chainService,
ForkFetcher: chainService,
FinalizationFetcher: chainService,
Expand Down
8 changes: 7 additions & 1 deletion beacon-chain/rpc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test")

go_library(
name = "go_default_library",
srcs = ["service.go"],
srcs = [
"service.go",
"tls.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/rpc",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
Expand All @@ -30,11 +33,14 @@ go_library(
"//proto/slashing:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
"//shared/rand:go_default_library",
"//shared/roughtime:go_default_library",
"//shared/traceutil:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//recovery:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//tracing/opentracing:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_prometheus//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//plugin/ocgrpc:go_default_library",
Expand Down
85 changes: 54 additions & 31 deletions beacon-chain/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,49 +52,51 @@ func init() {

// Service defining an RPC server for a beacon node.
type Service struct {
ctx context.Context
cancel context.CancelFunc
beaconDB db.HeadAccessDatabase
headFetcher blockchain.HeadFetcher
forkFetcher blockchain.ForkFetcher
finalizationFetcher blockchain.FinalizationFetcher
participationFetcher blockchain.ParticipationFetcher
genesisTimeFetcher blockchain.TimeFetcher
genesisFetcher blockchain.GenesisFetcher
attestationReceiver blockchain.AttestationReceiver
blockReceiver blockchain.BlockReceiver
powChainService powchain.Chain
chainStartFetcher powchain.ChainStartFetcher
insecureGRPC bool
mockEth1Votes bool
enableDebugRPCEndpoints bool
attestationsPool attestations.Pool
exitPool *voluntaryexits.Pool
slashingsPool *slashings.Pool
syncService sync.Checker
host string
port string
listener net.Listener
withCert string
withKey string
cancel context.CancelFunc
exitPool *voluntaryexits.Pool
slasherConn *grpc.ClientConn
stateGen *stategen.State
grpcServer *grpc.Server
canonicalStateChan chan *pbp2p.BeaconState
connectedRPCClients map[net.Addr]bool
incomingAttestation chan *ethpb.Attestation
credentialError error
p2p p2p.Broadcaster
pendingDepositFetcher depositcache.PendingDepositsFetcher
peersFetcher p2p.PeersProvider
peerManager p2p.PeerManager
p2p p2p.Broadcaster
credentialError error
depositFetcher depositcache.DepositFetcher
pendingDepositFetcher depositcache.PendingDepositsFetcher
stateNotifier statefeed.Notifier
blockNotifier blockfeed.Notifier
datadir string
withKey string
withCert string
ctx context.Context
operationNotifier opfeed.Notifier
slasherConn *grpc.ClientConn
port string
host string
syncService sync.Checker
listener net.Listener
slasherProvider string
attestationsPool attestations.Pool
slasherCert string
slasherCredentialError error
chainStartFetcher powchain.ChainStartFetcher
powChainService powchain.Chain
blockReceiver blockchain.BlockReceiver
attestationReceiver blockchain.AttestationReceiver
genesisFetcher blockchain.GenesisFetcher
genesisTimeFetcher blockchain.TimeFetcher
participationFetcher blockchain.ParticipationFetcher
finalizationFetcher blockchain.FinalizationFetcher
forkFetcher blockchain.ForkFetcher
headFetcher blockchain.HeadFetcher
beaconDB db.HeadAccessDatabase
slasherClient slashpb.SlasherClient
stateGen *stategen.State
connectedRPCClients map[net.Addr]bool
peerManager p2p.PeerManager
}

// Config options for the beacon node RPC server.
Expand All @@ -103,6 +105,7 @@ type Config struct {
Port string
CertFlag string
KeyFlag string
DataDir string
BeaconDB db.HeadAccessDatabase
HeadFetcher blockchain.HeadFetcher
ForkFetcher blockchain.ForkFetcher
Expand All @@ -115,6 +118,7 @@ type Config struct {
GenesisTimeFetcher blockchain.TimeFetcher
GenesisFetcher blockchain.GenesisFetcher
EnableDebugRPCEndpoints bool
InsecureGRPC bool
MockEth1Votes bool
AttestationsPool attestations.Pool
ExitPool *voluntaryexits.Pool
Expand Down Expand Up @@ -147,9 +151,11 @@ func NewService(ctx context.Context, cfg *Config) *Service {
participationFetcher: cfg.ParticipationFetcher,
genesisTimeFetcher: cfg.GenesisTimeFetcher,
genesisFetcher: cfg.GenesisFetcher,
datadir: cfg.DataDir,
attestationReceiver: cfg.AttestationReceiver,
blockReceiver: cfg.BlockReceiver,
p2p: cfg.Broadcaster,
insecureGRPC: cfg.InsecureGRPC,
peersFetcher: cfg.PeersFetcher,
peerManager: cfg.PeerManager,
powChainService: cfg.POWChainService,
Expand Down Expand Up @@ -208,6 +214,7 @@ func (s *Service) Start() {
)),
}
grpc_prometheus.EnableHandlingTimeHistogram()

if s.withCert != "" && s.withKey != "" {
creds, err := credentials.NewServerTLSFromFile(s.withCert, s.withKey)
if err != nil {
Expand All @@ -216,10 +223,26 @@ func (s *Service) Start() {
}
opts = append(opts, grpc.Creds(creds))
} else {
log.Warn("You are using an insecure gRPC server. If you are running your beacon node and " +
"validator on the same machines, you can ignore this message. If you want to know " +
"how to enable secure connections, see: https://docs.prylabs.network/docs/prysm-usage/secure-grpc")
if s.insecureGRPC {
log.Warn("You are using an insecure gRPC server. If you are running your beacon node and " +
"validator on the same machines, you can ignore this message. If you want to know " +
"how to enable secure connections, see: https://docs.prylabs.network/docs/prysm-usage/secure-grpc")
} else {
// Generate self-signed certs by default.
certPath, certKeyPath, err := generateSelfSignedCerts(s.datadir)
if err != nil {
log.Fatalf("Could not generate self-signed, secure gRPC certificates: %v", err)
}
creds, err := credentials.NewServerTLSFromFile(certPath, certKeyPath)
if err != nil {
log.Errorf("Could not load TLS keys: %s", err)
s.credentialError = err
}
opts = append(opts, grpc.Creds(creds))
log.Info("Establishing secure gRPC server using self-signed certificates")
}
}

s.grpcServer = grpc.NewServer(opts...)

validatorServer := &validator.Server{
Expand Down
93 changes: 93 additions & 0 deletions beacon-chain/rpc/tls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package rpc

import (
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"os"
"path"
"time"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/rand"
"github.com/prysmaticlabs/prysm/shared/roughtime"
)

const (
rsaBits = 2048
validFor = 365 * 24 * time.Hour
)

var (
selfSignedCertName = "beacon.pem"
selfSignedCertKeyName = "key.pem"
)

// Generates self-signed certificates at a datadir path. This function
// returns the paths of the cert.pem and key.pem files that
// were generated as a result.
func generateSelfSignedCerts(datadir string) (string, string, error) {
priv, err := rsa.GenerateKey(rand.NewGenerator(), rsaBits)
if err != nil {
return "", "", errors.Wrap(err, "nailed to generate private key")
}

notBefore := roughtime.Now()
notAfter := notBefore.Add(validFor)

serialNumber := big.NewInt(int64(rand.NewGenerator().Int() % 128))
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Prysm"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
template.IPAddresses = append(template.IPAddresses, net.ParseIP("127.0.0.1"))

template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign

derBytes, err := x509.CreateCertificate(rand.NewGenerator(), &template, &template, &priv.PublicKey, priv)
if err != nil {
return "", "", errors.Wrap(err, "failed to create x509 certificate")
}

certPath := path.Join(datadir, selfSignedCertName)
certKeyPath := path.Join(datadir, selfSignedCertKeyName)
certOut, err := os.Create(certPath)
if err != nil {
return "", "", errors.Wrapf(err, "failed to open %s for writing", certPath)
}
if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return "", "", errors.Wrapf(err, "failed to write data to %s", certPath)
}
if err := certOut.Close(); err != nil {
return "", "", errors.Wrapf(err, "error closing write buffer: %s", certPath)
}
log.WithField("certPath", certPath).Info("Wrote self-signed certificate file")

keyOut, err := os.OpenFile(certKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return "", "", errors.Wrapf(err, "failed to open %s for writing", certKeyPath)
}
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return "", "", errors.Wrap(err, "unable to marshal private key")
}
if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
return "", "", errors.Wrapf(err, "failed to write data to %s", certKeyPath)
}
if err := keyOut.Close(); err != nil {
return "", "", errors.Wrapf(err, "error closing write buffer: %s", certKeyPath)
}
log.WithField("certKeyPath", certKeyPath).Info("Wrote self-signed certificate key file")
return certPath, certKeyPath, nil
}
1 change: 1 addition & 0 deletions beacon-chain/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var appHelpFlagGroups = []flagGroup{
cmd.ConfigFileFlag,
cmd.ChainConfigFileFlag,
cmd.GrpcMaxCallRecvMsgSizeFlag,
cmd.InsecureGRPCFlag,
},
},
{
Expand Down
8 changes: 7 additions & 1 deletion shared/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,13 @@ var (
// GrpcMaxCallRecvMsgSizeFlag defines the max call message size for GRPC
GrpcMaxCallRecvMsgSizeFlag = &cli.IntFlag{
Name: "grpc-max-msg-size",
Usage: "Integer to define max recieve message call size (default: 4194304 (for 4MB))",
Usage: "Integer to define max receive message call size (default: 4194304 (for 4MB))",
Value: 1 << 22,
}
// InsecureGRPCFlag defines using an insecure gRPC connection (not recommended).
InsecureGRPCFlag = &cli.BoolFlag{
Name: "insecure-grpc-flag",
Usage: "Utilize an insecure grpc connection (not recommended)",
Value: false,
}
)