config+lnd: introduce new invoice-only macaroon

In this commit, we wrap up the prior ones and introduce config
settings, as well as proper generation for a new invoice-only macaroon.
All prior invoice path rules are also properly enforced of this new
invoice.macaroon.
This commit is contained in:
Olaoluwa Osuntokun 2018-03-20 16:50:08 -07:00
parent a07579c541
commit 4c0dcdafa5
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 73 additions and 28 deletions

@ -35,6 +35,7 @@ const (
defaultTLSKeyFilename = "tls.key"
defaultAdminMacFilename = "admin.macaroon"
defaultReadMacFilename = "readonly.macaroon"
defaultInvoiceMacFilename = "invoice.macaroon"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "lnd.log"
@ -57,14 +58,17 @@ const (
)
var (
defaultLndDir = btcutil.AppDataDir("lnd", false)
defaultConfigFile = filepath.Join(defaultLndDir, defaultConfigFilename)
defaultDataDir = filepath.Join(defaultLndDir, defaultDataDirname)
defaultTLSCertPath = filepath.Join(defaultLndDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(defaultLndDir, defaultTLSKeyFilename)
defaultAdminMacPath = filepath.Join(defaultLndDir, defaultAdminMacFilename)
defaultReadMacPath = filepath.Join(defaultLndDir, defaultReadMacFilename)
defaultLogDir = filepath.Join(defaultLndDir, defaultLogDirname)
defaultLndDir = btcutil.AppDataDir("lnd", false)
defaultConfigFile = filepath.Join(defaultLndDir, defaultConfigFilename)
defaultDataDir = filepath.Join(defaultLndDir, defaultDataDirname)
defaultLogDir = filepath.Join(defaultLndDir, defaultLogDirname)
defaultTLSCertPath = filepath.Join(defaultLndDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(defaultLndDir, defaultTLSKeyFilename)
defaultAdminMacPath = filepath.Join(defaultLndDir, defaultAdminMacFilename)
defaultReadMacPath = filepath.Join(defaultLndDir, defaultReadMacFilename)
defaultInvoiceMacPath = filepath.Join(defaultLndDir, defaultInvoiceMacFilename)
defaultBtcdDir = btcutil.AppDataDir("btcd", false)
defaultBtcdRPCCertFile = filepath.Join(defaultBtcdDir, "rpc.cert")
@ -150,6 +154,7 @@ type config struct {
NoMacaroons bool `long:"no-macaroons" description:"Disable macaroon authentication"`
AdminMacPath string `long:"adminmacaroonpath" description:"Path to write the admin macaroon for lnd's RPC and REST services if it doesn't exist"`
ReadMacPath string `long:"readonlymacaroonpath" description:"Path to write the read-only macaroon for lnd's RPC and REST services if it doesn't exist"`
InvoiceMacPath string `long:"invoicemacaroonpath" description:"Path to the invoice-only macaroon for lnd's RPC and REST services if it doesn't exist"`
LogDir string `long:"logdir" description:"Directory to log output."`
RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections"`
@ -205,15 +210,16 @@ type config struct {
// 4) Parse CLI options and overwrite/add any specified options
func loadConfig() (*config, error) {
defaultCfg := config{
LndDir: defaultLndDir,
ConfigFile: defaultConfigFile,
DataDir: defaultDataDir,
DebugLevel: defaultLogLevel,
TLSCertPath: defaultTLSCertPath,
TLSKeyPath: defaultTLSKeyPath,
AdminMacPath: defaultAdminMacPath,
ReadMacPath: defaultReadMacPath,
LogDir: defaultLogDir,
LndDir: defaultLndDir,
ConfigFile: defaultConfigFile,
DataDir: defaultDataDir,
DebugLevel: defaultLogLevel,
TLSCertPath: defaultTLSCertPath,
TLSKeyPath: defaultTLSKeyPath,
AdminMacPath: defaultAdminMacPath,
InvoiceMacPath: defaultInvoiceMacPath,
ReadMacPath: defaultReadMacPath,
LogDir: defaultLogDir,
Bitcoin: &chainConfig{
MinHTLC: defaultBitcoinMinHTLCMSat,
BaseFee: defaultBitcoinBaseFeeMSat,
@ -282,6 +288,7 @@ func loadConfig() (*config, error) {
defaultCfg.TLSCertPath = filepath.Join(lndDir, defaultTLSCertFilename)
defaultCfg.TLSKeyPath = filepath.Join(lndDir, defaultTLSKeyFilename)
defaultCfg.AdminMacPath = filepath.Join(lndDir, defaultAdminMacFilename)
defaultCfg.InvoiceMacPath = filepath.Join(lndDir, defaultInvoiceMacFilename)
defaultCfg.ReadMacPath = filepath.Join(lndDir, defaultReadMacFilename)
defaultCfg.LogDir = filepath.Join(lndDir, defaultLogDirname)
}
@ -327,6 +334,7 @@ func loadConfig() (*config, error) {
cfg.TLSKeyPath = cleanAndExpandPath(cfg.TLSKeyPath)
cfg.AdminMacPath = cleanAndExpandPath(cfg.AdminMacPath)
cfg.ReadMacPath = cleanAndExpandPath(cfg.ReadMacPath)
cfg.InvoiceMacPath = cleanAndExpandPath(cfg.InvoiceMacPath)
cfg.LogDir = cleanAndExpandPath(cfg.LogDir)
cfg.BtcdMode.Dir = cleanAndExpandPath(cfg.BtcdMode.Dir)
cfg.LtcdMode.Dir = cleanAndExpandPath(cfg.LtcdMode.Dir)
@ -591,10 +599,19 @@ func loadConfig() (*config, error) {
// directory has changed from the default path, then we'll also update
// the path for the macaroons to be generated.
if cfg.DataDir != defaultDataDir && cfg.AdminMacPath == defaultAdminMacPath {
cfg.AdminMacPath = filepath.Join(cfg.DataDir, defaultAdminMacFilename)
cfg.AdminMacPath = filepath.Join(
cfg.DataDir, defaultAdminMacFilename,
)
}
if cfg.DataDir != defaultDataDir && cfg.ReadMacPath == defaultReadMacPath {
cfg.ReadMacPath = filepath.Join(cfg.DataDir, defaultReadMacFilename)
cfg.ReadMacPath = filepath.Join(
cfg.DataDir, defaultReadMacFilename,
)
}
if cfg.DataDir != defaultDataDir && cfg.InvoiceMacPath == defaultInvoiceMacPath {
cfg.InvoiceMacPath = filepath.Join(
cfg.DataDir, defaultInvoiceMacPath,
)
}
// Append the network type to the log directory so it is "namespaced"

46
lnd.go

@ -228,10 +228,15 @@ func lndMain() error {
srvrLog.Error(err)
return err
}
// Create macaroon files for lncli to use if they don't exist.
if !fileExists(cfg.AdminMacPath) && !fileExists(cfg.ReadMacPath) {
err = genMacaroons(ctx, macaroonService,
cfg.AdminMacPath, cfg.ReadMacPath)
if !fileExists(cfg.AdminMacPath) && !fileExists(cfg.ReadMacPath) &&
!fileExists(cfg.InvoiceMacPath) {
err = genMacaroons(
ctx, macaroonService, cfg.AdminMacPath,
cfg.ReadMacPath, cfg.InvoiceMacPath,
)
if err != nil {
ltndLog.Errorf("unable to create macaroon "+
"files: %v", err)
@ -751,12 +756,33 @@ func genCertPair(certFile, keyFile string) error {
// genMacaroons generates a pair of macaroon files; one admin-level and one
// read-only. These can also be used to generate more granular macaroons.
func genMacaroons(ctx context.Context, svc *macaroons.Service, admFile,
roFile string) error {
func genMacaroons(ctx context.Context, svc *macaroons.Service,
admFile, roFile, invoiceFile string) error {
// First, we'll generate a macaroon that only allows the caller to
// access invoice related calls. This is useful for merchants and other
// services to allow an isolated instance that can only query and
// modify invoices.
invoiceMac, err := svc.Oven.NewMacaroon(
ctx, bakery.LatestVersion, nil, invoicePermissions...,
)
if err != nil {
return err
}
invoiceMacBytes, err := invoiceMac.M().MarshalBinary()
if err != nil {
return err
}
err = ioutil.WriteFile(invoiceFile, invoiceMacBytes, 0644)
if err != nil {
os.Remove(invoiceFile)
return err
}
// Generate the read-only macaroon and write it to a file.
roMacaroon, err := svc.Oven.NewMacaroon(ctx, bakery.LatestVersion, nil,
readPermissions...)
roMacaroon, err := svc.Oven.NewMacaroon(
ctx, bakery.LatestVersion, nil, readPermissions...,
)
if err != nil {
return err
}
@ -770,8 +796,10 @@ func genMacaroons(ctx context.Context, svc *macaroons.Service, admFile,
}
// Generate the admin macaroon and write it to a file.
admMacaroon, err := svc.Oven.NewMacaroon(ctx, bakery.LatestVersion,
nil, append(readPermissions, writePermissions...)...)
adminPermissions := append(readPermissions, writePermissions...)
admMacaroon, err := svc.Oven.NewMacaroon(
ctx, bakery.LatestVersion, nil, adminPermissions...,
)
if err != nil {
return err
}