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 6 commits into
base: master
Choose a base branch
from

Conversation

aeddi
Copy link
Contributor

@aeddi aeddi commented Jan 20, 2025

This PR introduces the gnokms command with the gnokey backend.

To give you some context:

To do:

  • Check in with you (at least @zivkovicmilos and @kristovatlas) to see if the overall direction works for you
  • Discuss how to pass the keys for mutual auth to the node and gnokms, and then implement it
  • Talk about then implement the integration with the node
    // If an address is provided, listen on the socket for a connection from an
    // external signing process.
    if config.PrivValidatorListenAddr != "" {
    // FIXME: we should start services inside OnStart
    privValidator, err = createAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, logger)
    if err != nil {
    return nil, errors.Wrap(err, "error with private validator socket client")
    }
    }
    pubKey := privValidator.GetPubKey()
    if pubKey == nil {
    // TODO: GetPubKey should return errors - https://github.com/gnolang/gno/tm2/pkg/bft/issues/3602
    return nil, errors.New("could not retrieve public key from private validator")
    }
  • Make sure the pubkey method returns an error and refactor what needs to be refactored.
  • Add tests.
  • Write a decent README.

@aeddi aeddi self-assigned this Jan 20, 2025
@github-actions github-actions bot added 📦 🌐 tendermint v2 Issues or PRs tm2 related 📦 ⛰️ gno.land Issues or PRs gno.land package related labels Jan 20, 2025
@Gno2D2
Copy link
Collaborator

Gno2D2 commented Jan 20, 2025

🛠 PR Checks Summary

All Automated Checks passed. ✅

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

🟢 Maintainers must be able to edit this pull request (more info)

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)

If

🟢 Condition met
└── 🟢 The pull request was created from a fork (head branch repo: aeddi/gno)

Then

🟢 Requirement satisfied
└── 🟢 Maintainer can modify this pull request

Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission

@aeddi aeddi changed the title (WIP) feat: init gnokms tool with gnokey backend feat: init gnokms tool with gnokey backend Jan 20, 2025
Copy link

codecov bot commented Jan 20, 2025

@aeddi aeddi force-pushed the dev/aeddi/gnokms-gnokey-adapter branch from d0e356c to 4948bd8 Compare January 20, 2025 11:12
@aeddi
Copy link
Contributor Author

aeddi commented Jan 23, 2025

Today we had a call with @zivkovicmilos to discuss the current implementation of gnokms and the remote signer / private validator interface inherited from the Tendermint codebase, and we concluded the following:

  • The current unconventional connection model with the server dialing the client seems irrelevant from a security perspective and is very counterintuitive. It also poses implementation issues at several different levels (client initialization, server configuration, etc.). We believe it would be cleaner and healthier to modify this mechanism so that the server is launched and waits for client requests.
  • We think that the node should ensure that it never signs the same thing twice and that the remote signer should be completely stateless, with as little intelligence as possible, and should only sign what the node requests.
  • The current interface that differentiates between vote signing ⁠SignVote(chainID string, vote *Vote) and proposal signing ⁠SignProposal(chainID string, proposal *Proposal) does not seem relevant to us. We believe that the remote signer should simply sign bytes without adding more complexity.

@aeddi
Copy link
Contributor Author

aeddi commented Jan 24, 2025

Before proceeding, I would like to ask for your opinion on the best approach to adopt for the refactor.

Approach A

  1. GnoKMS takes the following parameters:
    • The ID of the unique signing key this instance will use to sign data
    • An address to listen on for incoming connections
    • Optionally, the necessary private/public keys for mutual authentication
  2. The validator node does not know its validator public key; it only takes the following parameters:
    • The address of the remote signer (GnoKMS) to connect to
    • Optionally, the necessary private/public keys for mutual authentication
  3. The node connects to the remote signer, authenticate, gets the validator public key then completes its initialization (the public key is required during node initialization)
  4. The node locally verifies if the votes/proposals it wants to sign are consistent (no double signing, no issues with height lower than the previous signature, etc.)
  5. The node then sends simple arbitrary data (a slice of bytes) to GnoKMS for it to sign
  6. GnoKMS returns the signature of the data in question without performing any checks

Advantages

  • The API is very simple
  • The attack surface is greatly reduced for the remote signer
  • GnoKMS can perform key rotations/changes without needing to coordinate with the node in advance

Approach B

  1. GnoKMS takes the following parameters:
    • The path of a keybase containing multiple different keys
    • An address to listen on for incoming connections
    • Optionally, the necessary private/public keys for mutual authentication
  2. The validator node already knows its public key; it only takes the following parameters:
    • The address of the remote signer (GnoKMS) to connect to
    • Optionally, the necessary private/public keys for mutual authentication
  3. The node initializes with its public key that it already knows, connects to the remote signer, authenticate, then request it to use the corresponding private key.

4, 5, 6. Same as in approach A

Advantages

  • A single instance of GnoKMS can sign with multiple different keys
  • The initialization of the node can occur independently of the connection to the remote signer

Personally, I prefer the approach A (more simple and secure IMO), but I want to anticipate potential alternatives before tackling the refactor.

Other questions

  • If the node loses connection to the remote signer, should it fail immediately, or should it simply continue running, attempting to reconnect to the remote signer every X seconds and fail to sign blocks in the meantime?
  • Should GnoKMS accept that multiple different nodes connect in parallel? Or do we want to enforce a 1:1 connection?

@Kouteki Kouteki removed the in focus label Feb 3, 2025
@Kouteki Kouteki added this to the 🚀 Mainnet beta launch milestone Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 🌐 tendermint v2 Issues or PRs tm2 related 📦 ⛰️ gno.land Issues or PRs gno.land package related
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

3 participants