Skip to content

Commit 2b33087

Browse files
authored
Merge pull request #140 from ellemouton/macaroonService
multi: use lndclient MacaroonService
2 parents dd4329d + 00a8a39 commit 2b33087

File tree

6 files changed

+52
-178
lines changed

6 files changed

+52
-178
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ make && make install
2121
```
2222

2323
## Usage
24-
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.
24+
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.
2525
```
2626
./faraday \
27-
--lnd.macaroonpath={full path to lnd's readonly.macaroon} \
27+
--lnd.macaroonpath={full path to lnd's admin.macaroon} \
2828
--lnd.tlscertpath={path to lnd cert} \
2929
--lnd.rpcserver={host:port of lnd's rpcserver}
3030
```

config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ var (
7676

7777
// defaultLndMacaroon is the default macaroon file we use to connect to
7878
// lnd.
79-
defaultLndMacaroon = "readonly.macaroon"
79+
defaultLndMacaroon = "admin.macaroon"
8080

8181
// DefaultLndDir is the default location where we look for lnd's tls and
8282
// macaroon files.
@@ -103,7 +103,7 @@ type LndConfig struct {
103103
// all of lnd's macaroons. The specified macaroon MUST have all
104104
// permissions that all the subservers use, otherwise permission errors
105105
// will occur.
106-
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."`
106+
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."`
107107

108108
// TLSCertPath is the path to the tls cert that faraday should use.
109109
TLSCertPath string `long:"tlscertpath" description:"Path to TLS cert"`

frdrpcserver/macaroons.go

Lines changed: 0 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
11
package frdrpcserver
22

33
import (
4-
"context"
5-
"fmt"
6-
"io/ioutil"
7-
"os"
84
"time"
9-
10-
"github.com/lightningnetwork/lnd/kvdb"
11-
"github.com/lightningnetwork/lnd/lnrpc"
12-
"github.com/lightningnetwork/lnd/macaroons"
13-
"github.com/lightningnetwork/lnd/rpcperms"
14-
"go.etcd.io/bbolt"
15-
"google.golang.org/grpc"
16-
"gopkg.in/macaroon-bakery.v2/bakery"
17-
18-
"github.com/lightninglabs/faraday/frdrpcserver/perms"
195
)
206

217
const (
@@ -30,27 +16,6 @@ const (
3016

3117
var (
3218

33-
// allPermissions is the list of all existing permissions that exist
34-
// for faraday's RPC. The default macaroon that is created on startup
35-
// contains all these permissions and is therefore equivalent to lnd's
36-
// admin.macaroon but for faraday.
37-
allPermissions = []bakery.Op{{
38-
Entity: "recommendation",
39-
Action: "read",
40-
}, {
41-
Entity: "report",
42-
Action: "read",
43-
}, {
44-
Entity: "audit",
45-
Action: "read",
46-
}, {
47-
Entity: "insights",
48-
Action: "read",
49-
}, {
50-
Entity: "rates",
51-
Action: "read",
52-
}}
53-
5419
// macDbDefaultPw is the default encryption password used to encrypt the
5520
// faraday macaroon database. The macaroon service requires us to set a
5621
// non-nil password so we set it to an empty string. This will cause the
@@ -62,124 +27,3 @@ var (
6227
// though.
6328
macDbDefaultPw = []byte("")
6429
)
65-
66-
// startMacaroonService starts the macaroon validation service, creates or
67-
// unlocks the macaroon database and creates the default macaroon if it doesn't
68-
// exist yet.
69-
func (s *RPCServer) startMacaroonService(createDefaultMacaroonFile bool) error {
70-
var err error
71-
s.macaroonDB, err = kvdb.GetBoltBackend(&kvdb.BoltBackendConfig{
72-
DBPath: s.cfg.FaradayDir,
73-
DBFileName: "macaroons.db",
74-
DBTimeout: macDatabaseOpenTimeout,
75-
})
76-
if err == bbolt.ErrTimeout {
77-
return fmt.Errorf("error while trying to open %s/%s: "+
78-
"timed out after %v when trying to obtain exclusive "+
79-
"lock - make sure no other faraday daemon process "+
80-
"(standalone or embedded in lightning-terminal) is "+
81-
"running", s.cfg.FaradayDir, "macaroons.db",
82-
macDatabaseOpenTimeout)
83-
}
84-
if err != nil {
85-
return fmt.Errorf("unable to load macaroon db: %v", err)
86-
}
87-
88-
// Create the macaroon authentication/authorization service.
89-
s.macaroonService, err = macaroons.NewService(
90-
s.macaroonDB, faradayMacaroonLocation, false,
91-
macaroons.IPLockChecker,
92-
)
93-
if err != nil {
94-
return fmt.Errorf("unable to set up macaroon authentication: "+
95-
"%v", err)
96-
}
97-
98-
// Try to unlock the macaroon store with the private password.
99-
err = s.macaroonService.CreateUnlock(&macDbDefaultPw)
100-
if err != nil {
101-
return fmt.Errorf("unable to unlock macaroon DB: %v", err)
102-
}
103-
104-
// There are situations in which we don't want a macaroon to be created
105-
// on disk (for example when running inside LiT stateless integrated
106-
// mode). For any other cases, we create macaroon files for the faraday
107-
// CLI in the default directory.
108-
if createDefaultMacaroonFile && !lnrpc.FileExists(s.cfg.MacaroonPath) {
109-
// We don't offer the ability to rotate macaroon root keys yet,
110-
// so just use the default one since the service expects some
111-
// value to be set.
112-
idCtx := macaroons.ContextWithRootKeyID(
113-
context.Background(), macaroons.DefaultRootKeyID,
114-
)
115-
116-
// We only generate one default macaroon that contains all
117-
// existing permissions (equivalent to the admin.macaroon in
118-
// lnd). Custom macaroons can be created through the bakery
119-
// RPC.
120-
faradayMac, err := s.macaroonService.Oven.NewMacaroon(
121-
idCtx, bakery.LatestVersion, nil, allPermissions...,
122-
)
123-
if err != nil {
124-
return err
125-
}
126-
frdMacBytes, err := faradayMac.M().MarshalBinary()
127-
if err != nil {
128-
return err
129-
}
130-
err = ioutil.WriteFile(s.cfg.MacaroonPath, frdMacBytes, 0644)
131-
if err != nil {
132-
if err := os.Remove(s.cfg.MacaroonPath); err != nil {
133-
log.Errorf("Unable to remove %s: %v",
134-
s.cfg.MacaroonPath, err)
135-
}
136-
return err
137-
}
138-
}
139-
140-
return nil
141-
}
142-
143-
// stopMacaroonService closes the macaroon database.
144-
func (s *RPCServer) stopMacaroonService() error {
145-
var shutdownErr error
146-
if err := s.macaroonService.Close(); err != nil {
147-
log.Errorf("Error closing macaroon service: %v", err)
148-
shutdownErr = err
149-
}
150-
151-
if err := s.macaroonDB.Close(); err != nil {
152-
log.Errorf("Error closing macaroon DB: %v", err)
153-
shutdownErr = err
154-
}
155-
156-
return shutdownErr
157-
}
158-
159-
// macaroonInterceptor creates gRPC server options with the macaroon security
160-
// interceptors.
161-
func (s *RPCServer) macaroonInterceptor() ([]grpc.ServerOption, error) {
162-
interceptor := rpcperms.NewInterceptorChain(log, false, nil)
163-
164-
err := interceptor.Start()
165-
if err != nil {
166-
return nil, err
167-
}
168-
169-
interceptor.SetWalletUnlocked()
170-
interceptor.AddMacaroonService(s.macaroonService)
171-
172-
for method, permissions := range perms.RequiredPermissions {
173-
err := interceptor.AddPermission(method, permissions)
174-
if err != nil {
175-
return nil, err
176-
}
177-
}
178-
179-
unaryInterceptor := interceptor.MacaroonUnaryServerInterceptor()
180-
streamInterceptor := interceptor.MacaroonStreamServerInterceptor()
181-
return []grpc.ServerOption{
182-
grpc.UnaryInterceptor(unaryInterceptor),
183-
grpc.StreamInterceptor(streamInterceptor),
184-
}, nil
185-
}

frdrpcserver/rpcserver.go

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

2323
proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
2424
"github.com/lightninglabs/lndclient"
25-
"github.com/lightningnetwork/lnd/kvdb"
2625
"github.com/lightningnetwork/lnd/macaroons"
2726
"google.golang.org/grpc"
2827
"google.golang.org/grpc/credentials"
@@ -33,6 +32,7 @@ import (
3332
"github.com/lightninglabs/faraday/chain"
3433
"github.com/lightninglabs/faraday/fiat"
3534
"github.com/lightninglabs/faraday/frdrpc"
35+
"github.com/lightninglabs/faraday/frdrpcserver/perms"
3636
"github.com/lightninglabs/faraday/recommend"
3737
"github.com/lightninglabs/faraday/resolutions"
3838
"github.com/lightninglabs/faraday/revenue"
@@ -107,8 +107,7 @@ type RPCServer struct {
107107
// restServer is the REST proxy server.
108108
restServer *http.Server
109109

110-
macaroonService *macaroons.Service
111-
macaroonDB kvdb.Backend
110+
macaroonService *lndclient.MacaroonService
112111

113112
restCancel func()
114113
wg sync.WaitGroup
@@ -181,16 +180,38 @@ func (s *RPCServer) Start() error {
181180
}
182181
}()
183182

183+
// Set up the macaroon service.
184+
var err error
185+
s.macaroonService, err = lndclient.NewMacaroonService(
186+
&lndclient.MacaroonServiceConfig{
187+
DBPath: s.cfg.FaradayDir,
188+
DBFileName: "macaroons.db",
189+
DBTimeout: macDatabaseOpenTimeout,
190+
MacaroonLocation: faradayMacaroonLocation,
191+
MacaroonPath: s.cfg.MacaroonPath,
192+
Checkers: []macaroons.Checker{
193+
macaroons.IPLockChecker,
194+
},
195+
RequiredPerms: perms.RequiredPermissions,
196+
DBPassword: macDbDefaultPw,
197+
LndClient: &s.cfg.Lnd,
198+
EphemeralKey: lndclient.SharedKeyNUMS,
199+
KeyLocator: lndclient.SharedKeyLocator,
200+
})
201+
if err != nil {
202+
return fmt.Errorf("error creating macroon service: %v", err)
203+
}
204+
184205
// Start the macaroon service and let it create its default macaroon in
185206
// case it doesn't exist yet.
186-
if err := s.startMacaroonService(true); err != nil {
207+
if err := s.macaroonService.Start(); err != nil {
187208
return fmt.Errorf("error starting macaroon service: %v", err)
188209
}
189-
shutdownFuncs["macaroon"] = s.stopMacaroonService
210+
shutdownFuncs["macaroon"] = s.macaroonService.Stop
190211

191212
// First we add the security interceptor to our gRPC server options that
192213
// checks the macaroons for validity.
193-
serverOpts, err := s.macaroonInterceptor()
214+
unaryInterceptor, streamInterceptor, err := s.macaroonService.Interceptors()
194215
if err != nil {
195216
return fmt.Errorf("error with macaroon interceptor: %v", err)
196217
}
@@ -200,8 +221,11 @@ func (s *RPCServer) Start() error {
200221
// use tls.NewListener(). Otherwise we run into the ALPN error with non-
201222
// golang clients.
202223
tlsCredentials := credentials.NewTLS(s.cfg.TLSServerConfig)
203-
serverOpts = append(serverOpts, grpc.Creds(tlsCredentials))
204-
s.grpcServer = grpc.NewServer(serverOpts...)
224+
s.grpcServer = grpc.NewServer(
225+
grpc.UnaryInterceptor(unaryInterceptor),
226+
grpc.StreamInterceptor(streamInterceptor),
227+
grpc.Creds(tlsCredentials),
228+
)
205229

206230
// Start the gRPC RPCServer listening for HTTP/2 connections.
207231
log.Info("Starting gRPC listener")
@@ -303,16 +327,18 @@ func (s *RPCServer) Start() error {
303327
// for REST (if enabled), instead of creating an own mux and HTTP server, we
304328
// register to an existing one.
305329
func (s *RPCServer) StartAsSubserver(lndClient lndclient.LndServices,
306-
createDefaultMacaroonFile bool) error {
330+
withMacaroonService bool) error {
307331

308332
if atomic.AddInt32(&s.started, 1) != 1 {
309333
return errServerAlreadyStarted
310334
}
311335

312-
// Start the macaroon service and let it create its default macaroon in
313-
// case it doesn't exist yet.
314-
if err := s.startMacaroonService(createDefaultMacaroonFile); err != nil {
315-
return fmt.Errorf("error starting macaroon service: %v", err)
336+
if withMacaroonService {
337+
// Start the macaroon service and let it create its default
338+
// macaroon in case it doesn't exist yet.
339+
if err := s.macaroonService.Start(); err != nil {
340+
return fmt.Errorf("error starting macaroon service: %v", err)
341+
}
316342
}
317343

318344
s.cfg.Lnd = lndClient
@@ -328,6 +354,10 @@ func (s *RPCServer) StartAsSubserver(lndClient lndclient.LndServices,
328354
func (s *RPCServer) ValidateMacaroon(ctx context.Context,
329355
requiredPermissions []bakery.Op, fullMethod string) error {
330356

357+
if s.macaroonService == nil {
358+
return fmt.Errorf("macaroon service not yet initialised")
359+
}
360+
331361
// Delegate the call to faraday's own macaroon validator service.
332362
return s.macaroonService.ValidateMacaroon(
333363
ctx, requiredPermissions, fullMethod,
@@ -348,8 +378,10 @@ func (s *RPCServer) Stop() error {
348378
}
349379
}
350380

351-
if err := s.stopMacaroonService(); err != nil {
352-
log.Errorf("Error stopping macaroon service: %v", err)
381+
if s.macaroonService != nil {
382+
if err := s.macaroonService.Stop(); err != nil {
383+
log.Errorf("Error stopping macaroon service: %v", err)
384+
}
353385
}
354386

355387
// Stop the grpc server and wait for all go routines to terminate.

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ require (
1010
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display
1111
github.com/lightningnetwork/lnd v0.14.1-beta.0.20220324135938-0dcaa511a249
1212
github.com/lightningnetwork/lnd/cert v1.1.1
13-
github.com/lightningnetwork/lnd/kvdb v1.3.1
1413
github.com/shopspring/decimal v1.2.0
1514
github.com/stretchr/testify v1.7.0
1615
github.com/urfave/cli v1.22.4
17-
go.etcd.io/bbolt v1.3.6
1816
google.golang.org/grpc v1.38.0
1917
google.golang.org/protobuf v1.26.0
2018
gopkg.in/macaroon-bakery.v2 v2.0.1

itest/test_context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var (
3939
faradayArgs = []string{
4040
"--rpclisten=localhost:8465",
4141
"--network=regtest",
42-
"--lnd.macaroonpath=lnd-alice/data/chain/bitcoin/regtest/readonly.macaroon",
42+
"--lnd.macaroonpath=lnd-alice/data/chain/bitcoin/regtest/admin.macaroon",
4343
"--lnd.tlscertpath=lnd-alice/tls.cert",
4444
"--debuglevel=debug",
4545
"--connect_bitcoin",

0 commit comments

Comments
 (0)