Skip to content

lnd 0.11.1: allow custom macaroon to be used instead of requiring all subserver macaroons#19

Merged
guggero merged 7 commits intolightninglabs:lnd-11-1from
guggero:custom-macaroon
Nov 16, 2020
Merged

lnd 0.11.1: allow custom macaroon to be used instead of requiring all subserver macaroons#19
guggero merged 7 commits intolightninglabs:lnd-11-1from
guggero:custom-macaroon

Conversation

@guggero
Copy link
Copy Markdown
Contributor

@guggero guggero commented Oct 27, 2020

Addresses the problem described in lightninglabs/loop#299.

This PR adds two functionalities:

  1. Allow one custom macaroon to be specified (by providing CustomMacaroonPath instead of MacaroonDir in NewLndServices) instead of needing to have all lnd macaroons in the same directory. This allows users to use the admin.macaroon or a custom baked one.
  2. To make it easy to get a "macaroon recipe" for all required subservers, a new helper function MacaroonRecipe is added. This requires the lnrpc.Lightning.ListPermissions RPC which was only added in lnd v0.11.1.

NOTE: This PR is against the lnd-11-1 branch as it requires a compile-time dependency to that version. This code can also be used with older lnd versions but then the MacaroonRecipe function will throw an error.

@guggero guggero requested review from bhandras and carlaKC October 27, 2020 13:52
Copy link
Copy Markdown
Contributor

@carlaKC carlaKC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really excited to see this change come in!

Tried it out for Faraday here, and there's a little bit of a chicken-and-egg issue in that you need all of the macaroons to get a lndclient instance to then call MacaroonRecipe. If I'm using it in the way you were thinking we'd use it, could be missing the point?

What do you think about using a basic client rather than the lightning.Client interface for MacaroonRecipe? That could be a bit smoother for people who are starting up something like Faraday or Loop the first time, just give an admin macaroon and get the permissions needed, bake a new macaroon then run with it? If that wasn't the plan, it's still very useful to have to just update docs!

rpcCtx = s.adminMac.WithMacaroonAuth(rpcCtx)

perms, err := s.client.ListPermissions(
ctx, &lnrpc.ListPermissionsRequest{},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be rpcCtx, this fails with requires macaroon rn

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, great catch, thanks!

Copy link
Copy Markdown
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice changes @guggero!

// From the pointer type we can find out the interface, its name
// and what methods it declares.
ifaceType := reflect.TypeOf(ifacePtr).Elem()
serverName := strings.ReplaceAll(ifaceType.Name(), "Client", "")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that we can use reflection to gather method names but maybe a simple constant map of rpc -> method name would also suffice (and is easier to check/debug). Is perfectly fine as is, just a comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the list of exceptions keeps growing, I agree that we can switch over to a full map instead. But for now, this keeps the code quite small and also doesn't require you to add/change anything, if you add a new method that's called the same as the RPC it calls.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you add a new method that's called the same as the RPC it calls

nittynit: can see this being forgotten, maybe add a PR template with a reminder about this? I find that pretty useful. Can be in a follow up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unit tests should catch that. But to avoid an extra git push cycle I added it to the checklist 👍

@guggero
Copy link
Copy Markdown
Contributor Author

guggero commented Nov 16, 2020

Thanks for all the good input, I addressed all comments.

As mentioned, this bumps the requirement for lnd to v0.11.1-beta and is therefore on its own branch. But after merging this, I'll cherry pick the commits 3b8f352, e9d2375 and bc07123 to master and create a new tag. That way we can use the easier macaroon usage without needing to update lnd necessarily.

@guggero guggero requested review from bhandras and carlaKC November 16, 2020 10:53
Copy link
Copy Markdown
Member

@bhandras bhandras left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🌯

Copy link
Copy Markdown
Contributor

@carlaKC carlaKC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for getting to this! Going to be really helpful to have 🌹

// From the pointer type we can find out the interface, its name
// and what methods it declares.
ifaceType := reflect.TypeOf(ifacePtr).Elem()
serverName := strings.ReplaceAll(ifaceType.Name(), "Client", "")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you add a new method that's called the same as the RPC it calls

nittynit: can see this being forgotten, maybe add a PR template with a reminder about this? I find that pretty useful. Can be in a follow up.

With custom macaroon baking now available in lnd, it doesn't make sense
that a user must specify all subserver macaroons if a single, custom
macaroon is sufficient.
With this commit we add a new option to the lnd services that allows
users to specify a single, custom macaroon that overwrites the macaroon
path parameter.
To be able to write macaroon recipes, we need to be able to query all
existing RPC endpoints and the macaroon permissions they need. This
feature was only introduced in lnd v0.11.1-beta and therefore lifts the
required version lndclient needs to function.
To make it easy to bake custom macaroons for just the subservers that
lndclient supports, we add a function that returns all required macaroon
permissions for a given RPC package.
This function uses the ListPermissions RPC of lnd to query all existing
RPC method URIs and their required permissions. With some reflection
magic a subset of permissions is them assembled for the given package.
@guggero guggero merged commit e1d7fd7 into lightninglabs:lnd-11-1 Nov 16, 2020
@guggero guggero deleted the custom-macaroon branch November 16, 2020 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants