Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions cmd/waved/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@ func newRootCmd() *cobra.Command {
"run on mainnet (required when network=mainnet)",
)

// Escape hatch for deployments that terminate TLS and enforce auth
// at an external proxy: permit rpc.notls/rpc.no-macaroons on mainnet
// TCP listeners, which Validate() otherwise refuses.
f.Bool(
"allow-insecure-mainnet", cfg.AllowInsecureMainnet, "permit "+
"rpc.notls and rpc.no-macaroons on mainnet TCP "+
"listeners (transport security is expected to be "+
"provided externally)",
)

// Cap the per-round operator fee the client is willing to pay
// under the #270 seal-time fee handshake. Zero is rejected at
// config-load time as an explicit misconfiguration.
Expand Down
5 changes: 5 additions & 0 deletions sample-waved.conf
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
# Explicit opt-in for mainnet operation.
# allow-mainnet=false

# Permit rpc.notls and rpc.no-macaroons on mainnet TCP listeners, for
# deployments that terminate TLS and enforce authentication at an external
# proxy layer. Off by default; both options are otherwise refused on mainnet.
# allow-insecure-mainnet=false

# Maximum operator fee, in satoshis, accepted per seal-time quote.
# maxoperatorfeesat=1000000

Expand Down
20 changes: 17 additions & 3 deletions waved/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,16 @@ type Config struct {
// mainnet during development, since DefaultNetwork is "mainnet".
AllowMainnet bool `mapstructure:"allow-mainnet"`

// AllowInsecureMainnet permits the rpc.notls and rpc.no-macaroons
// options on mainnet TCP listeners. Both are refused on mainnet by
// default so a stray flag can't silently expose an unauthenticated,
// plaintext RPC surface. Deployments that terminate TLS and enforce
// authentication at an external proxy must set this explicitly to
// acknowledge that the daemon's own RPC listener runs without
// transport security. See the lightning-infra tracking issue for the
// deployment rationale.
AllowInsecureMainnet bool `mapstructure:"allow-insecure-mainnet"`

// Unroll configures the unilateral-exit subsystem.
Unroll *UnrollConfig `mapstructure:"unroll"`

Expand Down Expand Up @@ -1610,14 +1620,18 @@ func (c *Config) rpcMacaroonPath() string {

// validateRPCSecurity normalizes daemon RPC TLS and macaroon paths.
func (c *Config) validateRPCSecurity() error {
if c.Network == "mainnet" && c.RPC.Listener == nil {
if c.Network == "mainnet" && c.RPC.Listener == nil &&
!c.AllowInsecureMainnet {

if c.RPC.NoTLS {
return fmt.Errorf("rpc.notls cannot be used on " +
"mainnet TCP listeners")
"mainnet TCP listeners unless " +
"allow-insecure-mainnet is set")
}
if c.RPC.NoMacaroons {
return fmt.Errorf("rpc.no-macaroons cannot be used " +
"on mainnet TCP listeners")
"on mainnet TCP listeners unless " +
"allow-insecure-mainnet is set")
}
}

Expand Down
63 changes: 63 additions & 0 deletions waved/config_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,69 @@ func TestConfigValidateAllowsTestnet4InsecureRPC(t *testing.T) {
require.NoError(t, cfg.Validate())
}

// TestConfigValidateMainnetInsecureRPC verifies that rpc.notls and
// rpc.no-macaroons are refused on mainnet TCP listeners by default, and
// permitted once the operator opts in with allow-insecure-mainnet.
func TestConfigValidateMainnetInsecureRPC(t *testing.T) {
t.Parallel()

tests := []struct {
name string
noTLS bool
noMacaroons bool
override bool
wantErr string
}{
{
name: "notls refused by default",
noTLS: true,
wantErr: "rpc.notls cannot be used",
},
{
name: "no-macaroons refused by default",
noMacaroons: true,
wantErr: "rpc.no-macaroons cannot be used",
},
{
name: "notls allowed with override",
noTLS: true,
override: true,
},
{
name: "no-macaroons allowed with override",
noMacaroons: true,
override: true,
},
{
name: "both allowed with override",
noTLS: true,
noMacaroons: true,
override: true,
},
}

for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

cfg := DefaultConfig()
cfg.Network = "mainnet"
cfg.AllowMainnet = true
cfg.RPC.NoTLS = tc.noTLS
cfg.RPC.NoMacaroons = tc.noMacaroons
cfg.AllowInsecureMainnet = tc.override

err := cfg.Validate()
if tc.wantErr != "" {
require.ErrorContains(t, err, tc.wantErr)
} else {
require.NoError(t, err)
}
})
}
}

// TestConfigValidateWalletDefaults verifies Validate fills in the
// network-default Esplora/fee URL for the lwwallet and btcwallet backends
// when left empty, and still requires an explicit value on networks with no
Expand Down