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

feat: init gnokms tool with gnokey backend #3554

Draft
wants to merge 67 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
f228a15
chore: small cleanups and fixes
aeddi Jan 19, 2025
c6366c8
refactor: make logger init reusable
aeddi Jan 19, 2025
7401483
feat: gnokms + gnokey init
aeddi Jan 19, 2025
19f3dbb
feat: partial mutual auth implem
aeddi Jan 19, 2025
bdaddaf
feat: flags for conn params
aeddi Jan 19, 2025
02f40ff
chore: cleanup
aeddi Jan 20, 2025
26e1789
refactor: add error to privval GetPubKey
aeddi Jan 23, 2025
c384c0c
refactor: cleanup and rename Signer interface
aeddi Jan 31, 2025
2356fff
wip
aeddi Feb 6, 2025
723b233
wip
aeddi Feb 9, 2025
b84a02f
wip
aeddi Feb 12, 2025
10f09e6
wip
aeddi Feb 12, 2025
d49eeef
wip
aeddi Feb 16, 2025
7bc1c5f
wip
aeddi Feb 17, 2025
b545000
wip
aeddi Feb 17, 2025
a48fed5
wip
aeddi Feb 17, 2025
f2a78ef
wip
aeddi Feb 17, 2025
2b5e2e9
wip
aeddi Feb 17, 2025
edcf11f
docs(privval): rewrite doc according to the changes
aeddi Feb 17, 2025
b5be863
typo
aeddi Feb 17, 2025
824e883
wip
aeddi Feb 17, 2025
7f39cf7
wip
aeddi Feb 17, 2025
93407b0
wip
aeddi Feb 17, 2025
9332501
wip
aeddi Feb 18, 2025
08fc01d
wip
aeddi Feb 18, 2025
f1245eb
Merge branch 'master' into dev/aeddi/gnokms-gnokey-adapter
aeddi Feb 18, 2025
c731886
wip
aeddi Feb 18, 2025
ab5ad5b
Merge branch 'master' into dev/aeddi/gnokms-gnokey-adapter
aeddi Feb 18, 2025
66e83bd
wip
aeddi Feb 18, 2025
9d5b355
fix: gnodev import and signer usage
aeddi Feb 18, 2025
a4fb4ba
feat: improve logging
aeddi Feb 18, 2025
efc8b70
refactor: revert secret struct
aeddi Feb 18, 2025
030a273
feat: update node config to support remote signer
aeddi Feb 19, 2025
0fc3dd3
Merge branch 'master' into dev/aeddi/gnokms-gnokey-adapter
aeddi Feb 19, 2025
ba098cd
feat: add stringer for debug
aeddi Feb 19, 2025
f3767e5
fix: cleanup and fixes
aeddi Feb 19, 2025
1af82f8
feat: close the remote signer on node stop
aeddi Feb 20, 2025
b5d6295
fix: config test
aeddi Feb 20, 2025
5bb29e0
feat: split remote client and privval config
aeddi Feb 20, 2025
460a62f
feat: add auth to gnokms
aeddi Feb 20, 2025
5b9e740
Merge branch 'master' into dev/aeddi/gnokms-gnokey-adapter
aeddi Feb 20, 2025
2768648
chore: go mod tidy
aeddi Feb 20, 2025
0ce1e29
chore: lint
aeddi Feb 20, 2025
1de155d
chore: leftover
aeddi Feb 21, 2025
e2ee0e9
feat: finish authorized keys gnokms implem
aeddi Feb 21, 2025
9f7ac5d
chore: parameter ordre consistency
aeddi Feb 21, 2025
1f7b67a
fix: ensure nil target for amino unmarshal
aeddi Feb 21, 2025
e52bed1
chore: capitalize log for consistency
aeddi Feb 21, 2025
564b146
refactor: logger initialization for gnokms server
aeddi Feb 21, 2025
49de739
docs: print help message if auth keys not found
aeddi Feb 21, 2025
a794be2
feat: print validator info
aeddi Feb 21, 2025
210718b
docs: only print auth help for tcp listener
aeddi Feb 21, 2025
08a6983
feat: nodekey pub getter + explicit typing
aeddi Feb 23, 2025
7757fc2
feat: log listener start/stop on server
aeddi Feb 23, 2025
17f1a98
docs: add gnokms readme
aeddi Feb 23, 2025
e714601
feat: add Close method to Signer and PrivVal ifaces
aeddi Feb 23, 2025
3233621
refactor: remove useless filepath on key gen
aeddi Feb 24, 2025
7621f25
refactor: node key validation and file op
aeddi Feb 24, 2025
5a7024b
test: complete coverage of privval package
aeddi Feb 24, 2025
6737ff8
test: complete coverage of gnokms
aeddi Feb 25, 2025
4209cff
chore: go mod tidy
aeddi Feb 25, 2025
cbd1549
test(gnokms): cleanup
aeddi Feb 25, 2025
c4e3bac
feat(gnokms): print also bech32 validator info
aeddi Feb 26, 2025
2de0909
fix: reset deadline after secret conn
aeddi Feb 26, 2025
34f484a
chore: remove useless err check
aeddi Feb 26, 2025
3a77c57
test(gnokms): fix Github Actions inconsistent failure
aeddi Feb 26, 2025
7ef2d32
Merge branch 'master' into dev/aeddi/gnokms-gnokey-adapter
aeddi Feb 26, 2025
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
4 changes: 2 additions & 2 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,12 +661,12 @@ func (n *Node) genesisTxResultHandler(ctx sdk.Context, tx std.Tx, res sdk.Result

func newNodeConfig(tmc *tmcfg.Config, chainid, chaindomain string, appstate gnoland.GnoGenesisState) *gnoland.InMemoryNodeConfig {
// Create Mocked Identity
pv := gnoland.NewMockedPrivValidator()
pv := bft.NewMockPV()
genesis := gnoland.NewDefaultGenesisConfig(chainid, chaindomain)
genesis.AppState = appstate

// Add self as validator
self := pv.GetPubKey()
self, _ := pv.PubKey()
genesis.Validators = []bft.GenesisValidator{
{
Address: self.Address(),
Expand Down
18 changes: 18 additions & 0 deletions contribs/gnokms/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
rundep := go run -modfile ../../misc/devdeps/go.mod
golangci_lint := $(rundep) github.com/golangci/golangci-lint/cmd/golangci-lint


.PHONY: install
install:
go install .

.PHONY: build
build:
go build -o build/gnokms .

lint:
$(golangci_lint) --config ../../.github/golangci.yml run ./...

test:
go test $(GOTEST_FLAGS) -v ./...

115 changes: 115 additions & 0 deletions contribs/gnokms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# gnokms

`gnokms` is a simple Key Management System (KMS) designed to securely manage signing keys for [gnoland](../../gno.land/cmd/gnoland) (TM2) validator nodes. Rather than storing a key in plain text on disk, a validator can run a `gnokms` server in a separate process or on a separate machine, delegating the responsibility of securely storing the signing key and using it for remote signing.

`gnokms` also aims to provide several backends, including a local [gnokey](../../gno.land/cmd/gnokey) instance, a remote HSM, or a cloud-based KMS service.

Both TCP and Unix domain socket connections are supported for communication between the validator and the `gnokms` server. TCP connections are encrypted and can be mutually authenticated using Ed25519 keypairs and an authorized keys whitelist on both sides.

### Flowchart

```text
┌─────────────────────┐
│ │
┌─────────────┤ Cloud-based backend │
│ │ │
│ └─────────────────────┘
┌───────────────────┐ ┌───────┴───────┐ ┌─────────────────────┐
│ │ │ │ │ │
│ gnoland validator │◄─── UDS/TCP ───►│ gnokms server ├─────┤ gnokey backend │
│ │ │ │ │ │
└───────────────────┘ └───────┬───────┘ └─────────────────────┘
│ ┌─────────────────────┐
│ │ │
└─────────────┤ HSM backend │
│ │
└─────────────────────┘
```

## Getting Started

### Using `gnokms` with a gnoland validator

**Note:** The only supported backend for now is [gnokey](../../gno.land/cmd/gnokey), so the following instructions will use it.

1. Generate a signing key using [gnokey](../../gno.land/cmd/gnokey) if you do not already have one.
2. Start a `gnokms` server with the [gnokey](../../gno.land/cmd/gnokey) backend using:

```shell
$ gnokms gnokey '<key_name>' -listeners '<listen_address>'`
# <key_name> is the name of the key generated in step 1.
# <listen_address> is the address on which the server should listen (e.g., 'tcp://127.0.0.1:26659' or 'unix:///tmp/gnokms.sock').
```

3. Set the `gnokms` server address in the gnoland validator config using:

```shell
$ gnoland config set priv_validator.remote_signer.server_address '<gnokms_server_address>'
Updated configuration saved at gnoland-data/config/config.toml
```

### Genesis

When launching the `gnokms` server (e.g. step 2 from the previous section), it should display JSON containing validator information that is compatible with a genesis file. Example:

```shell
$ gnokms gnokey test1
Enter password to decrypt the key
2025-02-21T14:57:54.636+0100 INFO Genesis validator info:
{
"address": "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5",
"pub_key": {
"@type": "/tm.PubKeySecp256k1",
"value": "A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"
},
"power": "10",
"name": "gnokms_remote_signer"
}
```

If you need to manually edit a genesis file to include these infos, you can copy and paste them and potentially modify the default power and name.

### Mutual TCP Authentication

In the case of a TCP connection, the connection is encrypted. It can also be mutually authenticated to ensure an additional level of security (recommended outside of a testing or development context).

1. Generate a random keypair and an empty whitelist on the server side using:

```shell
$ gnokms auth generate
Generated auth keys file at path: "/Users/aeddi/Library/Application Support/gnokms/auth_keys.json"
```

2. Note the public key of the `gnokms` server displayed by the command:

```
$ gnokms auth identity
Server public key: "<gnokms_public_key>"
```

3. On the client side, add the `gnokms` server’s key to the validator’s whitelist using:

```shell
$ gnoland config set priv_validator.remote_signer.tcp_authorized_keys '<gnokms_public_key>'
Updated configuration saved at gnoland-data/config/config.toml
```

4. Note the validator’s public key displayed by the command:

```shell
$ gnoland secrets get node_id.pub_key
"<validator_public_key>"
```

5. On the server side, add the node’s key to the `gnokms` server whitelist using:

```shell
$ gnokms auth authorized add '<validator_public_key>'
Public key "<validator_public_key>" added to the authorized keys list.
```
42 changes: 42 additions & 0 deletions contribs/gnokms/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module github.com/gnolang/gno/contribs/gnokms

go 1.23.6

replace github.com/gnolang/gno => ../..

require (
github.com/gnolang/gno v0.0.0-00010101000000-000000000000
github.com/google/uuid v1.6.0
github.com/stretchr/testify v1.10.0
go.uber.org/zap v1.27.0
)

require (
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/btcsuite/btcd/btcutil v1.1.6 // indirect
github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/peterbourgon/ff/v3 v3.4.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v0.14.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
google.golang.org/grpc v1.69.4 // indirect
google.golang.org/protobuf v1.36.3 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading