Skip to content

Commit

Permalink
Granular rpc control (Allow list for RPC daemon) (#1341)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandrigin authored Nov 10, 2020
1 parent 546b91f commit ed96726
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 1,410 deletions.
27 changes: 27 additions & 0 deletions cmd/rpcdaemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,33 @@ WARN [11-05|09:03:47.911] Served conn=127.0.0.
WARN [11-05|09:03:47.911] Served conn=127.0.0.1:59754 method=eth_newPendingTransactionFilter reqid=6 t="9.053µs" err="the method eth_newPendingTransactionFilter does not exist/is not available"
```

## Allowing only specific methods (Allowlist)

In some cases you might want to only allow certain methods in the namespaces
and hide others. That is possible with `rpc.accessList` flag.

1. Create a file, say, `rules.json`

2. Add the following content

```json
{
"allow": [
"net_version",
"web3_eth_getBlockByHash"
]
}
```

3. Provide this file to the rpcdaemon using `--rpc.accessList` flag

```
> rpcdaemon --private.api.addr=localhost:9090 --http.api=eth,debug,net,web3 --rpc.accessList=rules.json
```

Now only these two methods are available.


## For Developers

### Code generation
Expand Down
47 changes: 29 additions & 18 deletions cmd/rpcdaemon/cli/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,23 @@ import (
)

type Flags struct {
PrivateApiAddr string
Chaindata string
SnapshotDir string
SnapshotMode string
HttpListenAddress string
TLSCertfile string
TLSCACert string
TLSKeyFile string
HttpPort int
HttpCORSDomain []string
HttpVirtualHost []string
API []string
Gascap uint64
MaxTraces uint64
TraceType string
WebsocketEnabled bool
PrivateApiAddr string
Chaindata string
SnapshotDir string
SnapshotMode string
HttpListenAddress string
TLSCertfile string
TLSCACert string
TLSKeyFile string
HttpPort int
HttpCORSDomain []string
HttpVirtualHost []string
API []string
Gascap uint64
MaxTraces uint64
TraceType string
WebsocketEnabled bool
RpcAllowListFilePath string
}

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -76,6 +77,11 @@ func RootCommand() (*cobra.Command, *Flags) {
rootCmd.PersistentFlags().Uint64Var(&cfg.MaxTraces, "trace.maxtraces", 200, "Sets a limit on traces that can be returned in trace_filter")
rootCmd.PersistentFlags().StringVar(&cfg.TraceType, "trace.type", "parity", "Specify the type of tracing [geth|parity*] (experimental)")
rootCmd.PersistentFlags().BoolVar(&cfg.WebsocketEnabled, "ws", false, "Enable Websockets")
rootCmd.PersistentFlags().StringVar(&cfg.RpcAllowListFilePath, "rpc.accessList", "", "Specify granular (method-by-method) API allowlist")

if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil {
panic(err)
}

return rootCmd, cfg
}
Expand Down Expand Up @@ -124,12 +130,17 @@ func StartRpcServer(ctx context.Context, cfg Flags, rpcAPI []rpc.API) error {
httpEndpoint := fmt.Sprintf("%s:%d", cfg.HttpListenAddress, cfg.HttpPort)

srv := rpc.NewServer()

allowListForRPC, err := parseAllowListForRPC(cfg.RpcAllowListFilePath)
if err != nil {
return err
}
srv.SetAllowList(allowListForRPC)

if err := node.RegisterApisFromWhitelist(rpcAPI, cfg.API, srv, false); err != nil {
return fmt.Errorf("could not start register RPC apis: %w", err)
}

var err error

httpHandler := node.NewHTTPHandlerStack(srv, cfg.HttpCORSDomain, cfg.HttpVirtualHost)
var wsHandler http.Handler
if cfg.WebsocketEnabled {
Expand Down
43 changes: 43 additions & 0 deletions cmd/rpcdaemon/cli/rpc_allow_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cli

import (
"encoding/json"
"io/ioutil"
"os"
"strings"

"github.com/ledgerwatch/turbo-geth/rpc"
)

type allowListFile struct {
Allow rpc.AllowList `json:"allow"`
}

func parseAllowListForRPC(path string) (rpc.AllowList, error) {
path = strings.TrimSpace(path)
if path == "" { // no file is provided
return nil, nil
}

file, err := os.Open(path)
if err != nil {
return nil, err
}
defer func() {
file.Close() //nolint: errcheck
}()

fileContents, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}

var allowListFileObj allowListFile

err = json.Unmarshal(fileContents, &allowListFileObj)
if err != nil {
return nil, err
}

return allowListFileObj.Allow, nil
}
Loading

0 comments on commit ed96726

Please sign in to comment.