mobileRumblefishLogo
Menu
desktopRumblefishLogo
Services
Products
Case studies
Careers
Resources
About us
Privatizing the private key in blockchain development with KMS Provider

Privatizing the private key in blockchain development with KMS Provider

Fri, Sep 10, 20216 min read

Category: Code Stories / AWS / Blockchain

The problem of the (not so) private key

Every collaborative development venture sooner or later faces the problem of effective, convenient, and secure key management. It gets even worse when it comes to blockchain projects, where the private key used to deploy smart contracts on production holds $$$ worth of ether and usually has the power to govern contracts. To keep the private key safe, a stakeholder would need to run production-related operations by himself. That’s the theory.

In practice, however, things look different. For many reasons, the stakeholder may not be - and usually isn’t - responsible for deploying, upgrading, or maintaining the code on production, so he entrusts the private key to another person, making it not so private anymore. Devs will ask this person to perform various operations on production by explaining what to do step by step or by providing scripts that require the private key to execute. I can think of many things that can possibly go wrong with this approach:

  • A person entrusted with the key leaves the project and the key needs to be shared with his successor which may not be so trustworthy,

  • The script given by a dev has malicious code that steals the private key, 

  • A person is overwhelmed with devs requests and makes a mistake during an upgrade,

  • A person loses the key...

And so on.

This sounds scary but due to lack of better tooling, this ‘methodology’ is widely used across Defi projects. What can we do about it?

KMS to the rescue

One of the most popular ways to deal with secrets in IT is to use “secret as a service” solutions like AWS Key Management Service which makes collaboration effective and secure. Using this service an AWS user can generate a new key and set which IAM users/roles can use it for signing. Most importantly, keys are generated by AWS and there is no way to export them. IAM users can be given access to use the key for signing without learning the underlying private key. In a sense, this workflow is similar to using a hardware wallet, but instead of using physical Ledger Nano, the developer requests that KMS generates a signature.

When a new team member needs to perform a deployment, they receive an appropriate IAM role and gets access to needed secrets. If a member leaves the team, the IAM role is revoked and there is no risk of disclosure. Using this workflow, the stakeholder of the project remains in control of the private key and can assign and revoke access to it when needed.

Using KMS in practice

It takes a bit of work to hook KMS and web3 providers together. Since we’re using this approach in Rumblefish across many projects, we’ve decided to open-source the tools we’re using and “pay it forward”. 

We’ve created two packages:

In order to create a new Ethereum account, the user needs to create a KMS key. When doing this in the AWS console, this is the correct way to configure the key:

The key needs to be:

  • Key type: Asymmetric

  • Key usage: Sign and Verify

  • Key spec: ECC_SECG_P256K1

The next step would be to learn the address of the account that you’ve just created. It’s derived from the public key of the key, but the transition is a tad complicated. 

We usually do it by configuring the provider using one of the packages above and performing the `eth_accounts` call. 

For example, when using a hardhat you can do:

$ hardhat console --network ropsten
Creating Typechain artifacts in directory types for target ethers-v5
Successfully generated Typechain artifacts!
Welcome to Node.js v12.22.6.
> getNamedAccounts().then(console.log)
Promise { <pending> }
> { deployer: '0x541dD0eC22fB1213d2C2B1fc83B5F302cEFF79A2' }

Alternatively using the regular web3 provider:

const { KMSProvider } = require('@rumblefishdev/eth-signer-kms')

const provider = new KMSProvider({
  providerOrUrl: `https://ropsten.infura.io/v3/${yourInfuraKey}`,
  keyId: yourKmsKeyId,
})
provider.getAddress().then(console.log)

For more details of the setup please refer to the Readme of the provider package you’re using.

Once you know your Ethereum address you can send some ETH to it and you’re all set to start using it for deployments and/or sending transactions.

Marek Kowalski
Marek Kowalski

CTO / Co-Founder

Daniel Cybułka
Daniel Cybułka

Blockchain Full Stack Developer

Categories
Follow Us