Merge pull request #438 from Roasbeef/mac-docs
docs: add new section for macaroons
This commit is contained in:
commit
e572c549be
126
docs/macaroons.md
Normal file
126
docs/macaroons.md
Normal file
@ -0,0 +1,126 @@
|
||||
As part of [the `lnd` 0.3-alpha
|
||||
release](https://github.com/lightningnetwork/lnd/releases/tag/v0.3-alpha), we
|
||||
have addressed [issue 20](https://github.com/lightningnetwork/lnd/issues/20),
|
||||
which is RPC authentictaion. Until this was implemented, all RPC calls to `lnd`
|
||||
were unauthenticated. To fix this, we've utilized
|
||||
[macaroons](https://research.google.com/pubs/pub41892.html), which are similar
|
||||
to cookies but more capable. This brief overview explains, at a basic level,
|
||||
how they work, how we use them for `lnd` authentication, and our future plans.
|
||||
|
||||
## What are macaroons?
|
||||
|
||||
You can think of a macaroon as a cookie, in a way. Cookies are small bits of
|
||||
data that your browser stores and sends to a particular website when it makes a
|
||||
request to that website. If you're logged into a website, that cookie can store
|
||||
a session ID, which the site can look up in its own database to check who you
|
||||
are and give you the appropriate content.
|
||||
|
||||
A macaroon is similar: it's a small bit of data that a client (like `lncli`)
|
||||
can send to a service (like `lnd`) to assert that it's allowed to perform an
|
||||
action. The service looks up the macaroon ID and verifies that the macaroon was
|
||||
initially signed with the service's root key. However, unlike a cookie, you can
|
||||
*delegate* a macaroon, or create a version of it that has more limited
|
||||
capabilities, and then send it to someone else to use.
|
||||
|
||||
Just like a cookie, a macaroon should be sent over a secure channel (such as a
|
||||
TLS-encrypted connection), which is why we've also begun enforcing TLS for RPC
|
||||
requests in this release. Before SSL was enforced on websites such as Facebook
|
||||
and Google, listening to HTTP sessions on wireless networks was one way to
|
||||
hijack the session and log in as that user, gaining access to the user's
|
||||
account. Macaroons are similar in that intercepting a macaroon in transit
|
||||
allows the interceptor to use the macaroon to gain all the privileges of the
|
||||
legitimate user.
|
||||
|
||||
## Macaroon delegation
|
||||
|
||||
A macaroon is delegated by adding restrictions (called caveats) and an
|
||||
authentication code similar to a signature (technically an HMAC) to it. The
|
||||
technical method of doing this is outside the scope of this overview
|
||||
documentation, but the macaroon paper linked above describes it quite well. The
|
||||
user must remember several things:
|
||||
|
||||
* Sharing a macaroon allows anyone in possession of that macaroon to use it to
|
||||
access the service (in our case, `lnd`) to do anything permitted by the
|
||||
macaroon. There is a specific type of restriction, called a "third party
|
||||
caveat," that requires an external service to verify the request; however,
|
||||
`lnd` doesn't currently implement those.
|
||||
|
||||
* If you add a caveat to a macaroon and share the resulting macaroon, the
|
||||
person receiving it cannot remove the caveat.
|
||||
|
||||
This is used in `lnd` in an interesting way. By default, when `lnd` starts, it
|
||||
creates two files which contain macaroons: a file called `admin.macaroon`,
|
||||
which contains a macaroon with no caveats, and a file called
|
||||
`readonly.macaroon`, which is the *same* macaroon but with an additional caveat
|
||||
that permits only methods that don't change the state of `lnd`.
|
||||
|
||||
## How macaroons are used by `lnd` and `lncli`.
|
||||
|
||||
On startup, `lnd` checks to see if the `admin.macaroon` and `readonly.macaroon`
|
||||
files exist. If they *both* don't exist, `lnd` updates its database with a new
|
||||
macaroon ID, generates the `admin.macaroon` file with that ID, and generates
|
||||
the `readonly.macaroon` file with the same ID but an additional caveat which
|
||||
restricts the caller to using only read-only methods. This means a few
|
||||
important things:
|
||||
|
||||
* You can delete the `admin.macaroon` and be left with only the
|
||||
`readonly.macaroon`, which can sometimes be useful (for example, if you want
|
||||
your `lnd` instance to run in autopilot mode and don't want to accidentally
|
||||
change its state).
|
||||
|
||||
* If you delete the data directory which contains the `macaroons.db` file, this
|
||||
invalidates the `admin.macaroon` and `readonly.macaroon` files. Invalid
|
||||
macaroon files give you errors like `cannot get macaroon: root key with id 0
|
||||
doesn't exist` or `verification failed: signature mismatch after caveat
|
||||
verification`.
|
||||
|
||||
You can also run `lnd` with the `--no-macaroons` option, which skips the
|
||||
creation of the macaroon files and all macaroon checks within the RPC server.
|
||||
This means you can still pass a macaroon to the RPC server with a client, but
|
||||
it won't be checked for validity.
|
||||
|
||||
Since `lnd` requires macaroons by default in order to call RPC methods, `lncli`
|
||||
now reads a macaroon and provides it in the RPC call. Unless the path is
|
||||
changed by the `--macaroonpath` option, `lncli` tries to read the macaroon from
|
||||
`~/.lnd/admin.macaroon` by default and will error if that file doesn't exist
|
||||
unless provided the `--no-macaroons` option. Keep this in mind when running
|
||||
`lnd` with `--no-macaroons`, as `lncli` will error out unless called the same
|
||||
way **or** `lnd` has generated a macaroon on a previous run without this
|
||||
option.
|
||||
|
||||
`lncli` also adds a caveat which makes it valid for only 60 seconds by default
|
||||
to help prevent replay in case the macaroon is somehow intercepted in
|
||||
transmission. This is unlikely with TLS, but can happen e.g. when using a PKI
|
||||
and network setup which allows inspection of encrypted traffic, and an attacker
|
||||
gets access to the traffic logs after interception. The default 60 second
|
||||
timeout can be changed with the `--macaroontimeout` option; this can be
|
||||
increased for making RPC calls between systems whose clocks are more than 60s
|
||||
apart.
|
||||
|
||||
## Future improvements to the `lnd` macaroon implementation
|
||||
|
||||
The existing macaroon implementation in `lnd` and `lncli` lays the groundwork
|
||||
for future improvements in functionality and security. We will add features
|
||||
such as:
|
||||
|
||||
* Improved replay protection for securing RPC calls
|
||||
|
||||
* Macaroon database encryption
|
||||
|
||||
* Root key rotation and possibly macaroon invalidation/rotation
|
||||
|
||||
* Tools to allow you to easily delegate macaroons in more flexible ways
|
||||
|
||||
* Additional restrictions, such as limiting payments to use (or not use)
|
||||
specific routes, channels, nodes, etc.
|
||||
|
||||
* Accounting-based macaroons, which can make an instance of `lnd` act almost
|
||||
like a bank for apps: for example, an app that pays to consume APIs whose
|
||||
budget is limited to the money it receives by providing an API/service
|
||||
|
||||
* Support for third-party caveats, which allows external plugins for
|
||||
authorization and authentication
|
||||
|
||||
With this new feature, we've started laying the groundwork for flexible
|
||||
authentication and authorization for RPC calls to `lnd`. We look forward to
|
||||
expanding its functionality to make it easy to develop secure apps.
|
Loading…
Reference in New Issue
Block a user