macaroons

package
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2020 License: MIT Imports: 18 Imported by: 0

README

macaroons

This is a more detailed, technical description of how macaroons work and how authentication and authorization is implemented in lnd.

For a more high-level overview see macaroons.md in the docs.

Root key

At startup, if the option --no-macaroons is not used, a Bolt DB key/value store named data/macaroons.db is created with a bucket named macrootkeys. In this DB the following two key/value pairs are stored:

  • Key 0: the encrypted root key (32 bytes).
    • If the root key does not exist yet, 32 bytes of pseudo-random data is generated and used.
  • Key enckey: the parameters used to derive a secret encryption key from a passphrase.
    • The following parameters are stored: <salt><digest><N><R><P>
      • salt: 32 byte of random data used as salt for the scrypt key derivation.
      • digest: sha256 hashed key derived from the scrypt operation. Is used to verify if the password is correct.
      • N, P, R: Parameters used for the scrypt operation.
    • The root key is symmetrically encrypted with the derived secret key, using the secretbox method of the library btcsuite/golangcrypto.
    • If the option --noseedbackup is used, then the default passphrase hello is used to encrypt the root key.

Generated macaroons

With the root key set up, lnd continues with creating three macaroon files:

  • invoice.macaroon: Grants read and write access to all invoice related gRPC commands (like generating an address or adding an invoice). Can be used for a web shop application for example. Paying an invoice is not possible, even if the name might suggest it. The permission offchain is needed to pay an invoice which is currently only granted in the admin macaroon.
  • readonly.macaroon: Grants read-only access to all gRPC commands. Could be given to a monitoring application for example.
  • admin.macaroon: Grants full read and write access to all gRPC commands. This is used by the lncli client.

These three macaroons all have the location field set to lnd and have no conditions/first party caveats or third party caveats set.

The access restrictions are implemented with a list of entity/action pairs that is mapped to the gRPC functions by the rpcserver.go. For example, the permissions for the invoice.macaroon looks like this:

	// invoicePermissions is a slice of all the entities that allows a user
	// to only access calls that are related to invoices, so: streaming
	// RPCs, generating, and listening invoices.
	invoicePermissions = []bakery.Op{
		{
			Entity: "invoices",
			Action: "read",
		},
		{
			Entity: "invoices",
			Action: "write",
		},
		{
			Entity: "address",
			Action: "read",
		},
		{
			Entity: "address",
			Action: "write",
		},
	}

Constraints / First party caveats

There are currently two constraints implemented that can be used by lncli to restrict the macaroon it uses to communicate with the gRPC interface. These can be found in constraints.go:

  • TimeoutConstraint: Set a timeout in seconds after which the macaroon is no longer valid. This constraint can be set by adding the parameter --macaroontimeout xy to the lncli command.
  • IPLockConstraint: Locks the macaroon to a specific IP address. This constraint can be set by adding the parameter --macaroonip a.b.c.d to the lncli command.

Bakery

As of lnd v0.9.0-beta there is a macaroon bakery available through gRPC and command line. Users can create their own macaroons with custom permissions if the provided default macaroons (admin, invoice and readonly) are not sufficient.

For example, a macaroon that is only allowed to manage peers would be created with the following command:

lncli bakemacaroon peers:read peers:write

A full and up-to-date list of available entity/action pairs can be found by looking at the rpcserver.go in the root folder of the project.

Upgrading from v0.8.0-beta or earlier

Users upgrading from a version prior to v0.9.0-beta might get a permission denied error when trying to use the lncli bakemacaroon command. This is because the bakery requires a new permission (macaroon/generate) to access. Users can obtain a new admin.macaroon that contains this permission by removing all three default macaroons (admin.macaroon, invoice.macaroon and readonly.macaroon, NOT the macaroons.db!) from their data/chain/<chain>/<network>/ directory inside the lnd data directory and restarting lnd.

Documentation

Index

Constants

View Source
const (
	// RootKeyLen is the length of a root key.
	RootKeyLen = 32
)

Variables

View Source
var (

	// ErrAlreadyUnlocked specifies that the store has already been
	// unlocked.
	ErrAlreadyUnlocked = fmt.Errorf("macaroon store already unlocked")

	// ErrStoreLocked specifies that the store needs to be unlocked with
	// a password.
	ErrStoreLocked = fmt.Errorf("macaroon store is locked")

	// ErrPasswordRequired specifies that a nil password has been passed.
	ErrPasswordRequired = fmt.Errorf("a non-nil password is required")
)
View Source
var (
	// DBFilename is the filename within the data directory which contains
	// the macaroon stores.
	DBFilename = "macaroons.db"
)

Functions

func AddConstraints

func AddConstraints(mac *macaroon.Macaroon, cs ...Constraint) (*macaroon.Macaroon, error)

AddConstraints returns new derived macaroon by applying every passed constraint and tightening its restrictions.

func IPLockChecker

func IPLockChecker() (string, checkers.Func)

IPLockChecker accepts client IP from the validation context and compares it with IP locked in the macaroon. It is of the `Checker` type.

func IPLockConstraint

func IPLockConstraint(ipAddr string) func(*macaroon.Macaroon) error

IPLockConstraint locks macaroon to a specific IP address. If address is an empty string, this constraint does nothing to accommodate default value's desired behavior.

func TimeoutConstraint

func TimeoutConstraint(seconds int64) func(*macaroon.Macaroon) error

TimeoutConstraint restricts the lifetime of the macaroon to the amount of seconds given.

Types

type Checker

type Checker func() (string, checkers.Func)

Checker type adds a layer of indirection over macaroon checkers. A Checker returns the name of the checker and the checker function; these are used to register the function with the bakery service's compound checker.

type Constraint

type Constraint func(*macaroon.Macaroon) error

Constraint type adds a layer of indirection over macaroon caveats.

type MacaroonCredential

type MacaroonCredential struct {
	*macaroon.Macaroon
}

MacaroonCredential wraps a macaroon to implement the credentials.PerRPCCredentials interface.

func NewMacaroonCredential

func NewMacaroonCredential(m *macaroon.Macaroon) MacaroonCredential

NewMacaroonCredential returns a copy of the passed macaroon wrapped in a MacaroonCredential struct which implements PerRPCCredentials.

func (MacaroonCredential) GetRequestMetadata

func (m MacaroonCredential) GetRequestMetadata(ctx context.Context,
	uri ...string) (map[string]string, error)

GetRequestMetadata implements the PerRPCCredentials interface. This method is required in order to pass the wrapped macaroon into the gRPC context. With this, the macaroon will be available within the request handling scope of the ultimate gRPC server implementation.

func (MacaroonCredential) RequireTransportSecurity

func (m MacaroonCredential) RequireTransportSecurity() bool

RequireTransportSecurity implements the PerRPCCredentials interface.

type RootKeyStorage

type RootKeyStorage struct {
	*bbolt.DB
	// contains filtered or unexported fields
}

RootKeyStorage implements the bakery.RootKeyStorage interface.

func NewRootKeyStorage

func NewRootKeyStorage(db *bbolt.DB) (*RootKeyStorage, error)

NewRootKeyStorage creates a RootKeyStorage instance. TODO(aakselrod): Add support for encryption of data with passphrase.

func (*RootKeyStorage) Close

func (r *RootKeyStorage) Close() error

Close closes the underlying database and zeroes the encryption key stored in memory.

func (*RootKeyStorage) CreateUnlock

func (r *RootKeyStorage) CreateUnlock(password *[]byte) error

CreateUnlock sets an encryption key if one is not already set, otherwise it checks if the password is correct for the stored encryption key.

func (*RootKeyStorage) Get

func (r *RootKeyStorage) Get(_ context.Context, id []byte) ([]byte, error)

Get implements the Get method for the bakery.RootKeyStorage interface.

func (*RootKeyStorage) RootKey

func (r *RootKeyStorage) RootKey(_ context.Context) ([]byte, []byte, error)

RootKey implements the RootKey method for the bakery.RootKeyStorage interface. TODO(aakselrod): Add support for key rotation.

type Service

type Service struct {
	bakery.Bakery
	// contains filtered or unexported fields
}

Service encapsulates bakery.Bakery and adds a Close() method that zeroes the root key service encryption keys, as well as utility methods to validate a macaroon against the bakery and gRPC middleware for macaroon-based auth.

func NewService

func NewService(dir string, checks ...Checker) (*Service, error)

NewService returns a service backed by the macaroon Bolt DB stored in the passed directory. The `checks` argument can be any of the `Checker` type functions defined in this package, or a custom checker if desired. This constructor prevents double-registration of checkers to prevent panics, so listing the same checker more than once is not harmful. Default checkers, such as those for `allow`, `time-before`, `declared`, and `error` caveats are registered automatically and don't need to be added.

func (*Service) Close

func (svc *Service) Close() error

Close closes the database that underlies the RootKeyStore and zeroes the encryption keys.

func (*Service) CreateUnlock

func (svc *Service) CreateUnlock(password *[]byte) error

CreateUnlock calls the underlying root key store's CreateUnlock and returns the result.

func (*Service) StreamServerInterceptor

func (svc *Service) StreamServerInterceptor(
	permissionMap map[string][]bakery.Op) grpc.StreamServerInterceptor

StreamServerInterceptor is a GRPC interceptor that checks whether the request is authorized by the included macaroons.

func (*Service) UnaryServerInterceptor

func (svc *Service) UnaryServerInterceptor(
	permissionMap map[string][]bakery.Op) grpc.UnaryServerInterceptor

UnaryServerInterceptor is a GRPC interceptor that checks whether the request is authorized by the included macaroons.

func (*Service) ValidateMacaroon

func (svc *Service) ValidateMacaroon(ctx context.Context,
	requiredPermissions []bakery.Op) error

ValidateMacaroon validates the capabilities of a given request given a bakery service, context, and uri. Within the passed context.Context, we expect a macaroon to be encoded as request metadata using the key "macaroon".

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL