Skip to content

Enable un-attended bootstrapping for pk agent start and pk bootstrap with PK_RECOVERY_CODE and PK_PASSWORD #202

Closed
@CMCDragonkai

Description

@CMCDragonkai

Block 1 from #194 (comment)

Aims to provide support for a Polykey instance to run unattended (i.e. without user prompt) when both the PK_RECOVERY_CODE and PK_PASSWORD variables are set.

Requirements of this design

  1. User has to supply a root password in order to encrypt a root key that is automatically generated
  2. If the user loses or forgets the root password, there is no way to decrypt the root key, there is no "Forget Password" functionality for decentralised application
  3. Provider an alternative way of recovering the root key
  4. The alternative is to store a BIP39 seed phrase that is used to generate the root key. If the user can supply a BIP39 seed phrase, this can be used to deterministically generate the root key, which doesn't require decrypting the root key and thus unlocking the keynode
  5. In an extreme case, the root key ciphertext file on disk is corrupted, and so decrypting it produces an incorrect root key, the seed phrase represents a backup of the root key
  6. Users must be notified to securely backup/store their root key, offer users to print it out as a "paper key" (like https://www.jabberwocky.com/software/paperkey/, we can even do funny things like QR codes)

Additional context

Note that the core function to generate a root key from a BIP39 seed is already available in our keys/utils.ts, see the function: generateDeterministicKeyPair. However it is not currently used by KeyManager, and not well tested.

Screenshot from Figma GUI design:

image

Specification

  1. Get the KeyManager to use the generateDeterministicKeyPair
  2. Make sure that this function generateDeterministicKeyPair is well tested
  3. Users are presented with a 24 word phrase to store and remember (prompt the user to store/print it)
  4. During the startup of the PK agent, the user has to supply the root password OR the seed phrase
  5. During session unlock, the user can supply the root password OR the seed phrase
  6. When a seed phrase is supplied, the root key is regenerated from the seed phrase, the root key ciphertext is not touched
  7. We must have a root key acceptance condition to know whether the root key has legitmately opened up a vault
  8. If it has, we can save/rewrite the root key as ciphertext over the ciphertext in the node state, which will resolve any root key ciphertext corruption

Regarding the root key acceptance, consider this idea:

  • Create a signed-message
  • Encrypt the message and save the message
  • If you can later decrypt the message, and check the the signature was signed by the root key and the message is what you expect
  • Then the root key is correct!
  • This message will need to be stored in the DB (as this is what is decrypted by the root key)

CLI command variables

Variables for CLI commands can be retrieved from:

  • file parameters
  • environment variables
  • src/config.ts
  • user prompt in STDIN

We require functions to retrieve the variables from each of these locations (created in src/bin/utils).

Variable precedence should be as follows: file parameters > environment variables/src/config.ts > default (STDIN prompt). We can use a sequence of coalescing operations to emulate this: for example, to retrieve the password, password = getFromParams() ?? getFromEnv ?? getFromStdin(). getFromStdin() here is expected to be the default, where we assume that a value will always be provided. If a default cannot exist for a particular variable, then throw an exception if none of the sources of variables can produce one.

See point 1 at #202 (comment) for further information.

Bootstrap process

Some components of the bootstrapping process need to be simplified:

Sub-Issues & Sub-PRs created

#283

checklist

  • Generate the keypair from the BIP menmonic
    • Generate a BIP mnemonic
    • generate keypair from menmonic
  • update keyManager to use new key generation method.
  • add a check that the mnemonic matches the nodeId for the node. if so we update the encrypted rootkey with the new password.
  • fix KeyManager to do the recovery process when a recovery code is provided with a password when node state exists.
  • tests
    • generating a keypair.
    • mnemonic deterministically recreates keypair.
    • can tell if mnemonic matches keypair/nodeId
    • can create new node from scratch, recreates nodeId and keypair.
    • can recover a keynode.
  • env variables implementation
    • bin/utils functions for variable retrieval
      • ~~getFromParams(): get variable from file parameter. Use str.trim() to remove trailing newlines/whitespace from the file (see 2 at Enable un-attended bootstrapping for pk agent start and pk bootstrap with PK_RECOVERY_CODE and PK_PASSWORD #202 (comment) for further information) ~~
      • getFromEnv(): get variable from environment variable
      • getFromConfig(): get variable from src/config.ts
      • getFromStdin(): get variable from user prompt
      • changed how this is handled, there are binUtils.getPassword and binUtils.getRecoveryCode. options for hosts and ports was created in src/bin/options.ts with their own defaults and env.
  • bootstrap process
    • use ENV variables for password and recovery code.
    • simplify bootstrapPolykeyState
    • tests for:
      • concurrent execution of 2x pk bootstrap
      • concurrent execution of 2x pk agent start
      • concurrent execution of pk bootstrap + pk agent start
    • simplify checkKeynodeState
  • implement --fresh flag: forces new keynode state, even if it already exists
    • pk agent start
    • pk bootstrap

Metadata

Metadata

Assignees

Labels

designRequires designenhancementNew feature or requestepicBig issue with multiple subissuesr&d:polykey:core activity 1Secret Vault Sharing and Secret History Management

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions