Skip to content

Commit 8a59081

Browse files
committed
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.
1 parent dd4329d commit 8a59081

File tree

6 files changed

+51
-177
lines changed

6 files changed

+51
-177
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: 46 additions & 14 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")
@@ -309,10 +333,12 @@ func (s *RPCServer) StartAsSubserver(lndClient lndclient.LndServices,
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 createDefaultMacaroonFile {
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)