Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement RPC Authentication #20

Roasbeef opened this issue Aug 26, 2016 · 3 comments

Implement RPC Authentication #20

Roasbeef opened this issue Aug 26, 2016 · 3 comments


Copy link

@Roasbeef Roasbeef commented Aug 26, 2016

Currently the RPC server is completely unauthenticated, responding to any and all requests sent to the server. Such behavior is fine for the current pre-alpha state the daemon is in, however future release should introduce a mechanism for authenticating privileged peers to the RPC server.

Two possible paths forward are first a simple password-based authentication mechanism, and a more advanced finer grained auth system which uses macaroons. The first path leads to ACL based security policies, while the second path leads to security policies implemented via bearer credentials.

In either case, gRPC's credentials package will need to be consulted in order to discern exactly how we'd like to integrate a proposed authentication mechanism into the daemon.

A tutorial for adding authentication into gRPC can be found here, and may prove useful in fixing this issue.

Password Hash:

The password based mechanism is likely the simplest option to start out with initially. Fields within the configuration would be added for one, or many rpcusers each with a rpcpasshash field belonging to it. Rather than storing the password in plaintext within the configuration, a hash of the password should instead be stored. This will likely utilize gRPC's transport based security, rather than the per-RPC auth methods.


The second proposed option is more involved, but is much more advanced and provides a very high degree of flexibility. Macaroons are decentralized bearer credentials with support for delegation, attenuation, and several other useful features. In this model, the per-RPC auth method would be used, and created macaroons can have fine-grained access policies. For example, a macaroon could be created that only allows sending 50,000 satoshis each day, over a particular channel, to a set of white-listed peers. Continuing, that macaroon can then be given to a friend, with a modification restricting it to only 10,000 satoshis a day. There's an existing macaroon implementation written in Go we may want to use. However it's a bit "heavy", therefore we may want to use a lightweight custom implementation for our purposes.

Copy link

@aakselrod aakselrod commented Nov 29, 2016

I'll take this one; will continue discussions with @Roasbeef on macaroon implementation.

Copy link

@aakselrod aakselrod commented Jan 5, 2017

Background on Macaroons

Macaroons are described by the paper Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud. In essence, they are bearer tokens issued by a target service (in our case, lnd) with restrictions (called caveats) describing what actions the bearer of the macaroon may be allowed to take and what criteria that bearer must meet in order to be allowed to take said actions. The bearer may delegate its permissions by adding caveats and forwarding the macaroon.

How Macaroons Work

Macaroons start as a nonce value, unique per macaroon, and an HMAC signature with a key known only to the target service. When a caveat is added, the original HMAC signature is removed but used as the key to sign the new caveat, and the new HMAC signature is appended. In this way, the recipient of the macaroon has no way of dropping previous caveats before attaching new ones, and only the target service can issue new macaroons.

First vs. Third Party Caveats

A caveat can be anything (some examples are defined by the Go Macaroon Bakery) that restricts actions a user may request a target service to take. For example, a caveat may require that the action requested is a read-only action (thus prohibiting write). This is a first-party caveat because the target service can directly verify the condition specified by the macaroon.

A caveat may also require a signature from a known key, attesting to the target service that the owner of the key approves the request based on its own criteria (with optional additional caveats). This is a third-party caveat because it requires the target service to trust the third party which owns the key. There are no use cases described below for third-party caveats, though some may exist. This could be an area with a lot of possibilities but would also require careful security analysis.

Potential Uses of Macaroons in lnd

Note that this is not an exhaustive list of potential use cases but only the ones I've been able to come up with based on the ideas listed by @Roasbeef above and the existing RPCs listed in the protobuf definition file for lnrpc. Other use cases may require additional types of caveats not described below with careful attention as to how they interact.

It's worth considering using the existing go-macaroon implementation as it's compatible with other implementations, which would make lnd easier to use from other languages that also support gRPC.

Server Administration

An lnd instance can create a macaroon for an administrative user that specifies no restrictions/caveats. The macaroon is as powerful as an administrator password or SSH keypair that allows full control of the instance and must be kept secret. The administrator may delegate any actions with additional restrictions, such as expiration times and allowed RPC commands, by adding caveats to the macaroon.

Payment Control

Macaroons are unable to represent the depletion of a resource inside the bearer token; accounting on the lnd side would be required to keep track of the current balance attached to a macaroon that permits limited spending or monetary commitment to a channel. Some potential use cases/scenarios follow.

Giving a process or user a one-time budget

An lnd instance could issue a macaroon to a process or user that represents a balance. The lnd instance would need to track the balance attached to the macaroon. The macaroon would have no caveat containing balance info. Each time the macaroon is used to make a payment, the RPC command would return the current balance of the macaroon. A macaroon's balance info could be deleted in the lnd database once it reaches zero, keeping the database pruned.

A delegated macaroon would need to include a caveat with an initial balance. First use of a delegated macaroon would need to subtract from the upstream macaroon's balance, and the new macaroon's balance would need to be tracked. The delegating process or user would also need to keep track of its balance locally and/or an RPC command to check a macaroon's balance would be needed (a balance check would also count as a first use of a delegated macaroon).

Additional consideration is required for the interaction between a macaroon that allows arbitrary spending, such as an administrator-level macaroon, and a budget macaroon described above. If an administrator were to spend enough money that the lnwallet's total balance is below that of the sum of all budget macaroons, the lnd instance would be effectively insolvent with respect to its local users.

One potential solution to this is to require all spending to be performed by budget macaroon, issue such macaroons only upon calling AddInvoice, and create nonzero balances for such macaroons only upon completion of the payment for the invoice. This opens up the possibility of each process or user being able to essentially have its own account on an instance of lnd. Such a capability could be useful in a situation where a process is selling access to a resource that in turn depends on buying access to other resources, e.g. a more mature version of the API market.

Giving a process or user the ability to manually open channels and send on-chain payments

On-chain and off-chain balances could be tracked using different macaroons, permitting the use of on-chain balances to be used for opening new channels. For example, an on-chain budget macaroon could be issued upon calling NewAddress or NewWitnessAddress, with a balance added to the macaroon when an on-chain transaction is committed sending funds to that address.

An on-chain budget macaroon's balance could be used to call OpenChannel, SendCoins, or SendMany. Calling OpenChannel would exchange the required on-chain balance for a new off-chain budget macaroon. An on-chain budget macaroon's balance could also be explicitly exchanged in whole or in part for an off-chain budget macaroon, freeing up that on-chain balance for the routing algorithm to automatically open new channels as needed.

Giving a process or user a periodic budget

An off-chain budget macaroon could be delegated with an initial balance (e.g. balance < 50000 measured in satoshis) and a time limit (e.g. time < 2017-01-06T00:00:00), re-delegating a macaroon after each expiration. A periodic garbage collection of macaroons could run on lnd, reassigning any remaining balance to the upstream macaroon and deleting the expired macaroon. Using a topological sort by dependency to delete macaroons would permit sub-delegation.

Limiting a macaroon's ability to send payments via specific channels or to specific peers

Caveats could be added limiting valid arguments to RPC calls to specific whitelisted values. For example, a caveat stating path[0] in {hop1, hop2} could restrict the holder of the macaroon to sending money only over the two channels specified by hop1 and hop2. A caveat stating path[-1] in {hop3, hop4} could restrict the holder to only sending money to Lightning nodes hop3 and hop4.

@Roasbeef Roasbeef added this to the v0.2-alpha milestone Feb 12, 2017
@Roasbeef Roasbeef removed this from the v0.2-alpha milestone Feb 28, 2017
Copy link
Member Author

@Roasbeef Roasbeef commented Aug 18, 2017

Fixed by #250.

We'll be making a few follow up issues to implement some more of the advanced functionality outlined in this original issue, as well as Alex's PR.

@Roasbeef Roasbeef closed this Aug 18, 2017
@aakselrod aakselrod mentioned this issue Aug 29, 2017
0 of 4 tasks complete
joostjager pushed a commit to joostjager/lnd that referenced this issue Nov 14, 2019

travis: update to go versions to 1.8.5, 1.9.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.