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

Add remote signing binary #9293

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
de5b1c1
lnd+lncfg: add outbound remote signer to config
ViktorTigerstrom May 14, 2024
759b817
lncfg: correct `DefaultRemoteSignerRPCTimeout` docs
ViktorTigerstrom May 20, 2024
33b8286
lnd: add new `remotesigner` macaroon entity
ViktorTigerstrom Aug 23, 2024
0ab64ff
walletrpc: add `SignCoordinatorStreams` RPC
ViktorTigerstrom May 14, 2024
7643663
rpcwallet: add `RemoteSigner` interface
ViktorTigerstrom May 14, 2024
80b0ad3
rpcwallet: add InboundRemoteSigner implementation
ViktorTigerstrom May 14, 2024
c375590
rpcwallet: add `RemoteSignerBuilder`
ViktorTigerstrom May 14, 2024
22173bb
rpcwallet: use `RemoteSigner` in RPCKeyRing
ViktorTigerstrom May 14, 2024
27cb7eb
lnd+rpcwallet: use `RemoteSigner` for health check
ViktorTigerstrom May 14, 2024
96569ea
rpcwallet: add `RemoteSignerClient` struct
ViktorTigerstrom May 14, 2024
e469852
f - rpcwallet: use GoroutineManager in remote signer signer client
ViktorTigerstrom Oct 31, 2024
66d22b3
rpcwallet: Add `RemoteSignerClientBuilder`
ViktorTigerstrom Sep 1, 2024
748c28a
lnd: add RemoteSignerClient instance on startup
ViktorTigerstrom May 14, 2024
16fdc25
lncfg: enable signerrole `signer-outbound`
ViktorTigerstrom May 14, 2024
bc1a52b
rpcwallet: add `SignCoordinator` struct
ViktorTigerstrom May 14, 2024
6257910
rpcwallet: add OutboundRemoteSigner implementation
ViktorTigerstrom May 14, 2024
d252d69
lnrpc: add AllowRemoteSigner WalletState proto
ViktorTigerstrom May 14, 2024
300047b
rpcperms: allow some RPCs before rpcActive state
ViktorTigerstrom May 14, 2024
3173439
rpcperms: fix SetServerActive function docs typo
ViktorTigerstrom May 14, 2024
73ee337
multi: enable RpcServer before dependencies exist
ViktorTigerstrom May 14, 2024
71f512c
multi: add `RemoteSigner` to walletrpc config
ViktorTigerstrom May 14, 2024
2213b95
walletrpc: implement `SignCoordinatorStreams` RPC
ViktorTigerstrom May 14, 2024
3f1bd7c
multi: add RemoteSigner before other dependencies
ViktorTigerstrom May 28, 2024
6694892
multi: add `ReadySignal` to `WalletController`
ViktorTigerstrom May 14, 2024
0221e2d
lnd: await remote signer connection on startup
ViktorTigerstrom May 28, 2024
5d51427
multi: enable signerrole `watchonly-outbound`
ViktorTigerstrom May 14, 2024
8d4233c
docs: add outbound signer to remote signing docs
ViktorTigerstrom May 13, 2024
1ce108a
docs: update release notes
ViktorTigerstrom Oct 31, 2024
ebe7025
lntest: separate creation/start of watch-only node
ViktorTigerstrom May 14, 2024
c9fcf12
itest: add outbound remote signer itest
ViktorTigerstrom May 14, 2024
bfdd795
itest: add testOutboundRSMacaroonEnforcement itest
ViktorTigerstrom Aug 28, 2024
5d6e40b
itest: wrap deriveCustomScopeAccounts at 80 chars
ViktorTigerstrom May 17, 2024
fd933d6
lncfg: Add `signer-inbound` `signerrole`
ViktorTigerstrom Nov 21, 2024
a563368
multi: Block non-whitelisted RPCs as remote signer
ViktorTigerstrom Nov 21, 2024
55d16b7
docs: recommend setting signer-inbound signerrole
ViktorTigerstrom Nov 21, 2024
c7784e4
multi: Add `lndsigner` binary
ViktorTigerstrom Nov 21, 2024
570b34f
lnd+lncfg: Add `SignerConfig`
ViktorTigerstrom Nov 21, 2024
2b03e06
lnd: load `SignerConfig` into `lndsigner`
ViktorTigerstrom Nov 21, 2024
76e4caf
f - lnd: Use interface for config loading instead
ViktorTigerstrom Nov 20, 2024
37e2ffc
make+scripts: add `lndsigner` to release script
ViktorTigerstrom Nov 21, 2024
bc0c0dc
docs: add `lndsigner` info to remote signing docs
ViktorTigerstrom Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
itest: add testOutboundRSMacaroonEnforcement itest
testOutboundRSMacaroonEnforcement tests that a valid macaroon including
the `remotesigner` entity is required to connect to a watch-only node
that uses an outbound remote signer, while the watch-only node is in the
state (WalletState_ALLOW_REMOTE_SIGNER) where it waits for the signer to
connect.
  • Loading branch information
ViktorTigerstrom committed Nov 21, 2024
commit bfdd7954103d7b406f27f9323d19553acecc1fb3
4 changes: 4 additions & 0 deletions itest/list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,10 @@ var allTestCases = []*lntest.TestCase{
Name: "outbound remote signer",
TestFunc: testOutboundRemoteSigner,
},
{
Name: "outbound remote signer macaroon enforcement",
TestFunc: testOutboundRSMacaroonEnforcement,
},
{
Name: "taproot coop close",
TestFunc: testTaprootCoopClose,
Expand Down
99 changes: 98 additions & 1 deletion itest/lnd_remote_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package itest
import (
"fmt"
"testing"
"time"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
Expand All @@ -13,6 +14,8 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet/rpcwallet"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -324,7 +327,7 @@ func testOutboundRemoteSigner(ht *lntest.HarnessTest) {
"--remotesigner.timeout=30s",
"--remotesigner.requesttimeout=30s",
}, commitArgs...),
password,
password, true,
)

// As the signer node will make an outbound connection to the
Expand Down Expand Up @@ -412,6 +415,100 @@ func testOutboundRemoteSigner(ht *lntest.HarnessTest) {
}
}

// testOutboundRSMacaroonEnforcement tests that a valid macaroon including
// the `remotesigner` entity is required to connect to a watch-only node that
// uses an outbound remote signer, while the watch-only node is in the state
// where it waits for the signer to connect.
func testOutboundRSMacaroonEnforcement(ht *lntest.HarnessTest) {
// Ensure that the watch-only node uses a configuration that requires an
// outbound remote signer during startup.
watchOnlyArgs := []string{
"--remotesigner.enable",
"--remotesigner.signerrole=watchonly-outbound",
"--remotesigner.timeout=15s",
"--remotesigner.requesttimeout=15s",
}

// Create the watch-only node. Note that we require authentication for
// the watch-only node, as we want to test that the macaroon enforcement
// works as expected.
watchOnly := ht.CreateNewNode("WatchOnly", watchOnlyArgs, nil, false)

startChan := make(chan error)

// Start the watch-only node in a goroutine as it requires a remote
// signer to connect before it can fully start.
go func() {
startChan <- watchOnly.Start(ht.Context())
}()

// Wait and ensure that the watch-only node reaches the state where
// it waits for the remote signer to connect, as this is the state where
// we want to test the macaroon enforcement.
err := wait.Predicate(func() bool {
if watchOnly.RPC == nil {
return false
}

state, err := watchOnly.RPC.State.GetState(
ht.Context(), &lnrpc.GetStateRequest{},
)
if err != nil {
return false
}

return state.State == lnrpc.WalletState_ALLOW_REMOTE_SIGNER
}, 5*time.Second)
require.NoError(ht, err)

// Set up a connection to the watch-only node. However, instead of using
// the watch-only node's admin macaroon, we'll use the invoice macaroon.
// The connection should not be allowed using this macaroon because it
// lacks the `remotesigner` entity required when the signer node
// connects to the watch-only node.
streamFeeder := rpcwallet.NewStreamFeeder(
watchOnly.Cfg.RPCAddr(), watchOnly.Cfg.InvoiceMacPath,
watchOnly.Cfg.TLSCertPath, 10*time.Second,
)

stream, cleanup, err := streamFeeder.GetStream(ht.Context())
require.NoError(ht, err)

defer cleanup()

// Since we're using an unauthorized macaroon, we should expect to be
// denied access to the watch-only node.
_, err = stream.Recv()
require.ErrorContains(ht, err, "permission denied")

// Finally, connect a real signer to the watch-only node so that
// it can start up properly.
signerArgs := []string{
"--remotesigner.signerrole=signer-outbound",
"--remotesigner.timeout=30s",
"--remotesigner.requesttimeout=10s",
fmt.Sprintf(
"--remotesigner.rpchost=localhost:%d",
watchOnly.Cfg.RPCPort,
),
fmt.Sprintf(
"--remotesigner.tlscertpath=%s",
watchOnly.Cfg.TLSCertPath,
),
fmt.Sprintf(
"--remotesigner.macaroonpath=%s",
watchOnly.Cfg.AdminMacPath, // An authorized macaroon.
),
}

_ = ht.NewNode("Signer", signerArgs)

// Finally, wait and ensure that the watch-only node is able to start
// up properly.
err = <-startChan
require.NoError(ht, err, "Shouldn't error on watch-only node startup")
}

// deriveCustomScopeAccounts derives the first 255 default accounts of the custom lnd
// internal key scope.
func deriveCustomScopeAccounts(t *testing.T) []*lnrpc.WatchOnlyAccount {
Expand Down
6 changes: 3 additions & 3 deletions lntest/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ func (h *HarnessTest) NewNodeWithSeedEtcd(name string, etcdCfg *etcd.Config,
func (h *HarnessTest) NewNodeWatchOnly(name string, extraArgs []string,
password []byte, watchOnly *lnrpc.WatchOnly) *node.HarnessNode {

hn := h.CreateNewNode(name, extraArgs, password)
hn := h.CreateNewNode(name, extraArgs, password, true)

h.StartWatchOnly(hn, name, password, watchOnly)

Expand All @@ -833,9 +833,9 @@ func (h *HarnessTest) NewNodeWatchOnly(name string, extraArgs []string,
// CreateNodeWatchOnly creates a new node and asserts its creation. The function
// will only create the node and will not start it.
func (h *HarnessTest) CreateNewNode(name string, extraArgs []string,
password []byte) *node.HarnessNode {
password []byte, noAuth bool) *node.HarnessNode {

hn, err := h.manager.newNode(h.T, name, extraArgs, password, true)
hn, err := h.manager.newNode(h.T, name, extraArgs, password, noAuth)
require.NoErrorf(h, err, "unable to create new node for %s", name)

return hn
Expand Down