Skip to content

Commit

Permalink
main: integrate macaroons into config, startup, and RPC server
Browse files Browse the repository at this point in the history
  • Loading branch information
aakselrod authored and Roasbeef committed Aug 18, 2017
1 parent 662731e commit 922b065
Show file tree
Hide file tree
Showing 4 changed files with 414 additions and 33 deletions.
31 changes: 20 additions & 11 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
defaultDataDirname = "data"
defaultTLSCertFilename = "tls.cert"
defaultTLSKeyFilename = "tls.key"
defaultAdminMacFilename = "admin.macaroon"
defaultReadMacFilename = "readonly.macaroon"
defaultLogLevel = "info"
defaultLogDirname = "logs"
defaultLogFilename = "lnd.log"
Expand All @@ -36,12 +38,14 @@ const (
)

var (
lndHomeDir = btcutil.AppDataDir("lnd", false)
defaultConfigFile = filepath.Join(lndHomeDir, defaultConfigFilename)
defaultDataDir = filepath.Join(lndHomeDir, defaultDataDirname)
defaultTLSCertPath = filepath.Join(lndHomeDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(lndHomeDir, defaultTLSKeyFilename)
defaultLogDir = filepath.Join(lndHomeDir, defaultLogDirname)
lndHomeDir = btcutil.AppDataDir("lnd", false)
defaultConfigFile = filepath.Join(lndHomeDir, defaultConfigFilename)
defaultDataDir = filepath.Join(lndHomeDir, defaultDataDirname)
defaultTLSCertPath = filepath.Join(lndHomeDir, defaultTLSCertFilename)
defaultTLSKeyPath = filepath.Join(lndHomeDir, defaultTLSKeyFilename)
defaultAdminMacPath = filepath.Join(lndHomeDir, defaultAdminMacFilename)
defaultReadMacPath = filepath.Join(lndHomeDir, defaultReadMacFilename)
defaultLogDir = filepath.Join(lndHomeDir, defaultLogDirname)

btcdHomeDir = btcutil.AppDataDir("btcd", false)
defaultBtcdRPCCertFile = filepath.Join(btcdHomeDir, "rpc.cert")
Expand Down Expand Up @@ -88,11 +92,14 @@ type autoPilotConfig struct {
type config struct {
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`

ConfigFile string `long:"C" long:"configfile" description:"Path to configuration file"`
DataDir string `short:"b" long:"datadir" description:"The directory to store lnd's data within"`
TLSCertPath string `long:"tlscertpath" description:"Path to TLS certificate for lnd's RPC and REST services"`
TLSKeyPath string `long:"tlskeypath" description:"Path to TLS private key for lnd's RPC and REST services"`
LogDir string `long:"logdir" description:"Directory to log output."`
ConfigFile string `long:"C" long:"configfile" description:"Path to configuration file"`
DataDir string `short:"b" long:"datadir" description:"The directory to store lnd's data within"`
TLSCertPath string `long:"tlscertpath" description:"Path to TLS certificate for lnd's RPC and REST services"`
TLSKeyPath string `long:"tlskeypath" description:"Path to TLS private key for lnd's RPC and REST services"`
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"`
LogDir string `long:"logdir" description:"Directory to log output."`

Listeners []string `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 5656)"`
ExternalIPs []string `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"`
Expand Down Expand Up @@ -132,6 +139,8 @@ func loadConfig() (*config, error) {
DebugLevel: defaultLogLevel,
TLSCertPath: defaultTLSCertPath,
TLSKeyPath: defaultTLSKeyPath,
AdminMacPath: defaultAdminMacPath,
ReadMacPath: defaultReadMacPath,
LogDir: defaultLogDir,
PeerPort: defaultPeerPort,
RPCPort: defaultRPCPort,
Expand Down
64 changes: 63 additions & 1 deletion lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
"strconv"
"time"

"gopkg.in/macaroon-bakery.v1/bakery"
"gopkg.in/macaroon-bakery.v1/bakery/checkers"

"golang.org/x/net/context"

"google.golang.org/grpc"
Expand All @@ -24,6 +27,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcutil"
)
Expand Down Expand Up @@ -78,6 +82,30 @@ func lndMain() error {
}
defer chanDB.Close()

// Only process macaroons if --no-macaroons isn't set.
var macaroonService *bakery.Service
if !cfg.NoMacaroons {
// Create the macaroon authentication/authorization service.
macaroonService, err = macaroons.NewService(cfg.DataDir)
if err != nil {
srvrLog.Errorf("unable to create macaroon service: %v",
err)
return err
}

// Create macaroon files for lncli to use if they don't exist.
if !fileExists(cfg.AdminMacPath) &&
!fileExists(cfg.ReadMacPath) {
err = genMacaroons(macaroonService, cfg.AdminMacPath,
cfg.ReadMacPath)
if err != nil {
ltndLog.Errorf("unable to create macaroon "+
"files: %v", err)
return err
}
}
}

// With the information parsed from the configuration, create valid
// instances of the paertinent interfaces required to operate the
// Lightning Network Daemon.
Expand Down Expand Up @@ -197,7 +225,7 @@ func lndMain() error {

// Initialize, and register our implementation of the gRPC interface
// exported by the rpcServer.
rpcServer := newRPCServer(server)
rpcServer := newRPCServer(server, macaroonService)
if err := rpcServer.Start(); err != nil {
return err
}
Expand Down Expand Up @@ -375,3 +403,37 @@ func genCertPair(certFile, keyFile string) error {
rpcsLog.Infof("Done generating TLS certificates")
return nil
}

// 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(svc *bakery.Service, admFile, roFile string) error {
// Generate the admin macaroon and write it to a file.
admMacaroon, err := svc.NewMacaroon("", nil, nil)
if err != nil {
return err
}
admBytes, err := admMacaroon.MarshalBinary()
if err != nil {
return err
}
if err = ioutil.WriteFile(admFile, admBytes, 0600); err != nil {
return err
}

// Generate the read-only macaroon and write it to a file.
caveat := checkers.AllowCaveat(roPermissions...)
roMacaroon := admMacaroon.Clone()
if err = svc.AddCaveat(roMacaroon, caveat); err != nil {
return err
}
roBytes, err := roMacaroon.MarshalBinary()
if err != nil {
return err
}
if err = ioutil.WriteFile(roFile, roBytes, 0644); err != nil {
os.Remove(admFile)
return err
}

return nil
}
28 changes: 23 additions & 5 deletions networktest.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"sync"
"time"

macaroon "gopkg.in/macaroon.v1"

"golang.org/x/net/context"

"google.golang.org/grpc"
Expand All @@ -25,6 +27,7 @@ import (

"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/rpctest"
Expand Down Expand Up @@ -137,6 +140,8 @@ func newLightningNode(btcrpcConfig *btcrpcclient.ConnConfig, lndArgs []string) (
}
cfg.TLSCertPath = filepath.Join(cfg.DataDir, "tls.cert")
cfg.TLSKeyPath = filepath.Join(cfg.DataDir, "tls.key")
cfg.AdminMacPath = filepath.Join(cfg.DataDir, "admin.macaroon")
cfg.ReadMacPath = filepath.Join(cfg.DataDir, "readonly.macaroon")

cfg.PeerPort, cfg.RPCPort = generateListeningPorts()

Expand Down Expand Up @@ -177,6 +182,8 @@ func (l *lightningNode) genArgs() []string {
args = append(args, fmt.Sprintf("--tlscertpath=%v", l.cfg.TLSCertPath))
args = append(args, fmt.Sprintf("--tlskeypath=%v", l.cfg.TLSKeyPath))
args = append(args, fmt.Sprintf("--configfile=%v", l.cfg.DataDir))
args = append(args, fmt.Sprintf("--adminmacaroonpath=%v", l.cfg.AdminMacPath))
args = append(args, fmt.Sprintf("--readonlymacaroonpath=%v", l.cfg.ReadMacPath))

if l.extraArgs != nil {
args = append(args, l.extraArgs...)
Expand Down Expand Up @@ -247,23 +254,34 @@ func (l *lightningNode) Start(lndError chan error) error {
return err
}

// Wait until TLS certificate is created before using it, up to 20 sec.
// Wait until TLS certificate and admin macaroon are created before
// using them, up to 20 sec.
tlsTimeout := time.After(20 * time.Second)
for !fileExists(l.cfg.TLSCertPath) {
for !fileExists(l.cfg.TLSCertPath) || !fileExists(l.cfg.AdminMacPath) {
time.Sleep(100 * time.Millisecond)
select {
case <-tlsTimeout:
panic(fmt.Errorf("timeout waiting for TLS cert file " +
"to be created after 20 seconds"))
"and admin macaroon file to be created after " +
"20 seconds"))
default:
}
}
creds, err := credentials.NewClientTLSFromFile(l.cfg.TLSCertPath, "")
tlsCreds, err := credentials.NewClientTLSFromFile(l.cfg.TLSCertPath, "")
if err != nil {
return err
}
macBytes, err := ioutil.ReadFile(l.cfg.AdminMacPath)
if err != nil {
return err
}
mac := &macaroon.Macaroon{}
if err = mac.UnmarshalBinary(macBytes); err != nil {
return err
}
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithTransportCredentials(tlsCreds),
grpc.WithPerRPCCredentials(macaroons.NewMacaroonCredential(mac)),
grpc.WithBlock(),
grpc.WithTimeout(time.Second * 20),
}
Expand Down
Loading

0 comments on commit 922b065

Please sign in to comment.