127 lines
6.4 KiB
Markdown
127 lines
6.4 KiB
Markdown
|
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.
|