mirror of
https://github.com/lightninglabs/faraday.git
synced 2026-08-13 12:33:35 +02:00
multi: use lndclient MacaroonService
Since the code for creating and using a macaroon service is the same for multiple projects (pool, loop, faraday & litd), the code has been unified in lndclient. So this commit removes the macaroon service code and instead uses the lndclient code. Since the default key for the macaroon db is now a shared secret with LND, faraday requires LND's admin macaroon so that this secret can be derived. So this commit also updates all references of LND's `readme` macaroon to the `admin` macaroon.
This commit is contained in:
parent
dd4329d258
commit
8a59081473
6 changed files with 51 additions and 177 deletions
|
|
@ -21,10 +21,10 @@ make && make install
|
|||
```
|
||||
|
||||
## Usage
|
||||
Faraday connects to a single instance of lnd. It requires access to `lnd`'s `readonly.macaroon` and a valid TLS certificate. It will attempt to use the default `lnd` values if no command line flags are specified.
|
||||
Faraday connects to a single instance of lnd. It requires access to `lnd`'s `admin.macaroon` and a valid TLS certificate. It will attempt to use the default `lnd` values if no command line flags are specified.
|
||||
```
|
||||
./faraday \
|
||||
--lnd.macaroonpath={full path to lnd's readonly.macaroon} \
|
||||
--lnd.macaroonpath={full path to lnd's admin.macaroon} \
|
||||
--lnd.tlscertpath={path to lnd cert} \
|
||||
--lnd.rpcserver={host:port of lnd's rpcserver}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ var (
|
|||
|
||||
// defaultLndMacaroon is the default macaroon file we use to connect to
|
||||
// lnd.
|
||||
defaultLndMacaroon = "readonly.macaroon"
|
||||
defaultLndMacaroon = "admin.macaroon"
|
||||
|
||||
// DefaultLndDir is the default location where we look for lnd's tls and
|
||||
// macaroon files.
|
||||
|
|
@ -103,7 +103,7 @@ type LndConfig struct {
|
|||
// all of lnd's macaroons. The specified macaroon MUST have all
|
||||
// permissions that all the subservers use, otherwise permission errors
|
||||
// will occur.
|
||||
MacaroonPath string `long:"macaroonpath" description:"The full path to the single macaroon to use, either the readonly.macaroon or a custom baked one. Cannot be specified at the same time as macaroondir. A custom macaroon must contain ALL permissions required for all subservers to work, otherwise permission errors will occur."`
|
||||
MacaroonPath string `long:"macaroonpath" description:"The full path to the single macaroon to use, either the admin.macaroon or a custom baked one. Cannot be specified at the same time as macaroondir. A custom macaroon must contain ALL permissions required for all subservers to work, otherwise permission errors will occur."`
|
||||
|
||||
// TLSCertPath is the path to the tls cert that faraday should use.
|
||||
TLSCertPath string `long:"tlscertpath" description:"Path to TLS cert"`
|
||||
|
|
|
|||
|
|
@ -1,21 +1,7 @@
|
|||
package frdrpcserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"github.com/lightningnetwork/lnd/rpcperms"
|
||||
"go.etcd.io/bbolt"
|
||||
"google.golang.org/grpc"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
|
||||
"github.com/lightninglabs/faraday/frdrpcserver/perms"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -30,27 +16,6 @@ const (
|
|||
|
||||
var (
|
||||
|
||||
// allPermissions is the list of all existing permissions that exist
|
||||
// for faraday's RPC. The default macaroon that is created on startup
|
||||
// contains all these permissions and is therefore equivalent to lnd's
|
||||
// admin.macaroon but for faraday.
|
||||
allPermissions = []bakery.Op{{
|
||||
Entity: "recommendation",
|
||||
Action: "read",
|
||||
}, {
|
||||
Entity: "report",
|
||||
Action: "read",
|
||||
}, {
|
||||
Entity: "audit",
|
||||
Action: "read",
|
||||
}, {
|
||||
Entity: "insights",
|
||||
Action: "read",
|
||||
}, {
|
||||
Entity: "rates",
|
||||
Action: "read",
|
||||
}}
|
||||
|
||||
// macDbDefaultPw is the default encryption password used to encrypt the
|
||||
// faraday macaroon database. The macaroon service requires us to set a
|
||||
// non-nil password so we set it to an empty string. This will cause the
|
||||
|
|
@ -62,124 +27,3 @@ var (
|
|||
// though.
|
||||
macDbDefaultPw = []byte("")
|
||||
)
|
||||
|
||||
// startMacaroonService starts the macaroon validation service, creates or
|
||||
// unlocks the macaroon database and creates the default macaroon if it doesn't
|
||||
// exist yet.
|
||||
func (s *RPCServer) startMacaroonService(createDefaultMacaroonFile bool) error {
|
||||
var err error
|
||||
s.macaroonDB, err = kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
|
||||
DBPath: s.cfg.FaradayDir,
|
||||
DBFileName: "macaroons.db",
|
||||
DBTimeout: macDatabaseOpenTimeout,
|
||||
})
|
||||
if err == bbolt.ErrTimeout {
|
||||
return fmt.Errorf("error while trying to open %s/%s: "+
|
||||
"timed out after %v when trying to obtain exclusive "+
|
||||
"lock - make sure no other faraday daemon process "+
|
||||
"(standalone or embedded in lightning-terminal) is "+
|
||||
"running", s.cfg.FaradayDir, "macaroons.db",
|
||||
macDatabaseOpenTimeout)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load macaroon db: %v", err)
|
||||
}
|
||||
|
||||
// Create the macaroon authentication/authorization service.
|
||||
s.macaroonService, err = macaroons.NewService(
|
||||
s.macaroonDB, faradayMacaroonLocation, false,
|
||||
macaroons.IPLockChecker,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to set up macaroon authentication: "+
|
||||
"%v", err)
|
||||
}
|
||||
|
||||
// Try to unlock the macaroon store with the private password.
|
||||
err = s.macaroonService.CreateUnlock(&macDbDefaultPw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unlock macaroon DB: %v", err)
|
||||
}
|
||||
|
||||
// There are situations in which we don't want a macaroon to be created
|
||||
// on disk (for example when running inside LiT stateless integrated
|
||||
// mode). For any other cases, we create macaroon files for the faraday
|
||||
// CLI in the default directory.
|
||||
if createDefaultMacaroonFile && !lnrpc.FileExists(s.cfg.MacaroonPath) {
|
||||
// We don't offer the ability to rotate macaroon root keys yet,
|
||||
// so just use the default one since the service expects some
|
||||
// value to be set.
|
||||
idCtx := macaroons.ContextWithRootKeyID(
|
||||
context.Background(), macaroons.DefaultRootKeyID,
|
||||
)
|
||||
|
||||
// We only generate one default macaroon that contains all
|
||||
// existing permissions (equivalent to the admin.macaroon in
|
||||
// lnd). Custom macaroons can be created through the bakery
|
||||
// RPC.
|
||||
faradayMac, err := s.macaroonService.Oven.NewMacaroon(
|
||||
idCtx, bakery.LatestVersion, nil, allPermissions...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frdMacBytes, err := faradayMac.M().MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(s.cfg.MacaroonPath, frdMacBytes, 0644)
|
||||
if err != nil {
|
||||
if err := os.Remove(s.cfg.MacaroonPath); err != nil {
|
||||
log.Errorf("Unable to remove %s: %v",
|
||||
s.cfg.MacaroonPath, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopMacaroonService closes the macaroon database.
|
||||
func (s *RPCServer) stopMacaroonService() error {
|
||||
var shutdownErr error
|
||||
if err := s.macaroonService.Close(); err != nil {
|
||||
log.Errorf("Error closing macaroon service: %v", err)
|
||||
shutdownErr = err
|
||||
}
|
||||
|
||||
if err := s.macaroonDB.Close(); err != nil {
|
||||
log.Errorf("Error closing macaroon DB: %v", err)
|
||||
shutdownErr = err
|
||||
}
|
||||
|
||||
return shutdownErr
|
||||
}
|
||||
|
||||
// macaroonInterceptor creates gRPC server options with the macaroon security
|
||||
// interceptors.
|
||||
func (s *RPCServer) macaroonInterceptor() ([]grpc.ServerOption, error) {
|
||||
interceptor := rpcperms.NewInterceptorChain(log, false, nil)
|
||||
|
||||
err := interceptor.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
interceptor.SetWalletUnlocked()
|
||||
interceptor.AddMacaroonService(s.macaroonService)
|
||||
|
||||
for method, permissions := range perms.RequiredPermissions {
|
||||
err := interceptor.AddPermission(method, permissions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
unaryInterceptor := interceptor.MacaroonUnaryServerInterceptor()
|
||||
streamInterceptor := interceptor.MacaroonStreamServerInterceptor()
|
||||
return []grpc.ServerOption{
|
||||
grpc.UnaryInterceptor(unaryInterceptor),
|
||||
grpc.StreamInterceptor(streamInterceptor),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
|
@ -33,6 +32,7 @@ import (
|
|||
"github.com/lightninglabs/faraday/chain"
|
||||
"github.com/lightninglabs/faraday/fiat"
|
||||
"github.com/lightninglabs/faraday/frdrpc"
|
||||
"github.com/lightninglabs/faraday/frdrpcserver/perms"
|
||||
"github.com/lightninglabs/faraday/recommend"
|
||||
"github.com/lightninglabs/faraday/resolutions"
|
||||
"github.com/lightninglabs/faraday/revenue"
|
||||
|
|
@ -107,8 +107,7 @@ type RPCServer struct {
|
|||
// restServer is the REST proxy server.
|
||||
restServer *http.Server
|
||||
|
||||
macaroonService *macaroons.Service
|
||||
macaroonDB kvdb.Backend
|
||||
macaroonService *lndclient.MacaroonService
|
||||
|
||||
restCancel func()
|
||||
wg sync.WaitGroup
|
||||
|
|
@ -181,16 +180,38 @@ func (s *RPCServer) Start() error {
|
|||
}
|
||||
}()
|
||||
|
||||
// Set up the macaroon service.
|
||||
var err error
|
||||
s.macaroonService, err = lndclient.NewMacaroonService(
|
||||
&lndclient.MacaroonServiceConfig{
|
||||
DBPath: s.cfg.FaradayDir,
|
||||
DBFileName: "macaroons.db",
|
||||
DBTimeout: macDatabaseOpenTimeout,
|
||||
MacaroonLocation: faradayMacaroonLocation,
|
||||
MacaroonPath: s.cfg.MacaroonPath,
|
||||
Checkers: []macaroons.Checker{
|
||||
macaroons.IPLockChecker,
|
||||
},
|
||||
RequiredPerms: perms.RequiredPermissions,
|
||||
DBPassword: macDbDefaultPw,
|
||||
LndClient: &s.cfg.Lnd,
|
||||
EphemeralKey: lndclient.SharedKeyNUMS,
|
||||
KeyLocator: lndclient.SharedKeyLocator,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating macroon service: %v", err)
|
||||
}
|
||||
|
||||
// Start the macaroon service and let it create its default macaroon in
|
||||
// case it doesn't exist yet.
|
||||
if err := s.startMacaroonService(true); err != nil {
|
||||
if err := s.macaroonService.Start(); err != nil {
|
||||
return fmt.Errorf("error starting macaroon service: %v", err)
|
||||
}
|
||||
shutdownFuncs["macaroon"] = s.stopMacaroonService
|
||||
shutdownFuncs["macaroon"] = s.macaroonService.Stop
|
||||
|
||||
// First we add the security interceptor to our gRPC server options that
|
||||
// checks the macaroons for validity.
|
||||
serverOpts, err := s.macaroonInterceptor()
|
||||
unaryInterceptor, streamInterceptor, err := s.macaroonService.Interceptors()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error with macaroon interceptor: %v", err)
|
||||
}
|
||||
|
|
@ -200,8 +221,11 @@ func (s *RPCServer) Start() error {
|
|||
// use tls.NewListener(). Otherwise we run into the ALPN error with non-
|
||||
// golang clients.
|
||||
tlsCredentials := credentials.NewTLS(s.cfg.TLSServerConfig)
|
||||
serverOpts = append(serverOpts, grpc.Creds(tlsCredentials))
|
||||
s.grpcServer = grpc.NewServer(serverOpts...)
|
||||
s.grpcServer = grpc.NewServer(
|
||||
grpc.UnaryInterceptor(unaryInterceptor),
|
||||
grpc.StreamInterceptor(streamInterceptor),
|
||||
grpc.Creds(tlsCredentials),
|
||||
)
|
||||
|
||||
// Start the gRPC RPCServer listening for HTTP/2 connections.
|
||||
log.Info("Starting gRPC listener")
|
||||
|
|
@ -309,10 +333,12 @@ func (s *RPCServer) StartAsSubserver(lndClient lndclient.LndServices,
|
|||
return errServerAlreadyStarted
|
||||
}
|
||||
|
||||
// Start the macaroon service and let it create its default macaroon in
|
||||
// case it doesn't exist yet.
|
||||
if err := s.startMacaroonService(createDefaultMacaroonFile); err != nil {
|
||||
return fmt.Errorf("error starting macaroon service: %v", err)
|
||||
if createDefaultMacaroonFile {
|
||||
// Start the macaroon service and let it create its default
|
||||
// macaroon in case it doesn't exist yet.
|
||||
if err := s.macaroonService.Start(); err != nil {
|
||||
return fmt.Errorf("error starting macaroon service: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
s.cfg.Lnd = lndClient
|
||||
|
|
@ -328,6 +354,10 @@ func (s *RPCServer) StartAsSubserver(lndClient lndclient.LndServices,
|
|||
func (s *RPCServer) ValidateMacaroon(ctx context.Context,
|
||||
requiredPermissions []bakery.Op, fullMethod string) error {
|
||||
|
||||
if s.macaroonService == nil {
|
||||
return fmt.Errorf("macaroon service not yet initialised")
|
||||
}
|
||||
|
||||
// Delegate the call to faraday's own macaroon validator service.
|
||||
return s.macaroonService.ValidateMacaroon(
|
||||
ctx, requiredPermissions, fullMethod,
|
||||
|
|
@ -348,8 +378,10 @@ func (s *RPCServer) Stop() error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := s.stopMacaroonService(); err != nil {
|
||||
log.Errorf("Error stopping macaroon service: %v", err)
|
||||
if s.macaroonService != nil {
|
||||
if err := s.macaroonService.Stop(); err != nil {
|
||||
log.Errorf("Error stopping macaroon service: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the grpc server and wait for all go routines to terminate.
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -10,11 +10,9 @@ require (
|
|||
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
|
||||
github.com/lightningnetwork/lnd v0.14.1-beta.0.20220324135938-0dcaa511a249
|
||||
github.com/lightningnetwork/lnd/cert v1.1.1
|
||||
github.com/lightningnetwork/lnd/kvdb v1.3.1
|
||||
github.com/shopspring/decimal v1.2.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/urfave/cli v1.22.4
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
google.golang.org/grpc v1.38.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ var (
|
|||
faradayArgs = []string{
|
||||
"--rpclisten=localhost:8465",
|
||||
"--network=regtest",
|
||||
"--lnd.macaroonpath=lnd-alice/data/chain/bitcoin/regtest/readonly.macaroon",
|
||||
"--lnd.macaroonpath=lnd-alice/data/chain/bitcoin/regtest/admin.macaroon",
|
||||
"--lnd.tlscertpath=lnd-alice/tls.cert",
|
||||
"--debuglevel=debug",
|
||||
"--connect_bitcoin",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue