diff --git a/README.md b/README.md index 644ff5b..477a9a5 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,7 @@ It also includes a script for getting the emitted events from a transaction. ## Read returned value from tx [This example](/getting-tx-return-value) shows how to get the return value from a mined transaction. + +## AWS encrypted credentials + +[This example](/aws-encrypted-credentials) shows how to have encrypted private keys on an environment file. \ No newline at end of file diff --git a/aws-encrypted-credentials/.env.example b/aws-encrypted-credentials/.env.example new file mode 100644 index 0000000..db32461 --- /dev/null +++ b/aws-encrypted-credentials/.env.example @@ -0,0 +1,2 @@ +KMS_KEY_ID= +PRIVATE_KEY= \ No newline at end of file diff --git a/aws-encrypted-credentials/.gitignore b/aws-encrypted-credentials/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/aws-encrypted-credentials/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/aws-encrypted-credentials/README.md b/aws-encrypted-credentials/README.md new file mode 100644 index 0000000..4e3478e --- /dev/null +++ b/aws-encrypted-credentials/README.md @@ -0,0 +1,21 @@ +# AWS encrypted credentials + +This repository shows how you have encrypted environment credentials. Code on `hardhat.config.js` can be much cleaner, but its for demonstration purpose. + +Main idea here is to avoid having unencrypted private key on environment files: Avoid leaking credentials on github, npm, or while showing something on a video call. + +## Steps +1. Copy example environment file: +```bash +cp .env.example . env` +``` +2. Set up your `KMS_KEY_ID` on your `.env` +```bash +nano .env +``` +3. Run task to encrypt your private key +```bash +npx hardhat encrypt +``` +4. Copy output of encrypted private key into the `.env` file + diff --git a/aws-encrypted-credentials/contracts/Greeter.sol b/aws-encrypted-credentials/contracts/Greeter.sol new file mode 100644 index 0000000..8f67bdf --- /dev/null +++ b/aws-encrypted-credentials/contracts/Greeter.sol @@ -0,0 +1,23 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.7.0; + +import "hardhat/console.sol"; + + +contract Greeter { + string greeting; + + constructor(string memory _greeting) { + console.log("Deploying a Greeter with greeting:", _greeting); + greeting = _greeting; + } + + function greet() public view returns (string memory) { + return greeting; + } + + function setGreeting(string memory _greeting) public { + console.log("Changing greeting from '%s' to '%s'", greeting, _greeting); + greeting = _greeting; + } +} diff --git a/aws-encrypted-credentials/hardhat.config.js b/aws-encrypted-credentials/hardhat.config.js new file mode 100644 index 0000000..6baf367 --- /dev/null +++ b/aws-encrypted-credentials/hardhat.config.js @@ -0,0 +1,71 @@ +require("@nomiclabs/hardhat-waffle"); +require("dotenv").config(); +const inquirer = require('inquirer'); +const { KMS } = require('aws-sdk'); +const { utils } = require("ethers"); + +const DEFAULT_CLIENT_CONFIGURATION = { + apiVersion: '2014-11-01', + region: 'us-east-1', +}; + +const kms = new KMS(DEFAULT_CLIENT_CONFIGURATION); + +const encrypt = async (stringToEncrypt) => { + const data = await kms + .encrypt({ + KeyId: process.env.KMS_KEY_ID, + Plaintext: Buffer.from(stringToEncrypt), + }) + .promise(); + return data.CiphertextBlob.toString('base64'); +}; + +const decrypt = (encryptedString) => { + let decryptedInfo = undefined; + let kill = false; + kms.decrypt( + { + CiphertextBlob: Buffer.from(encryptedString, 'base64'), + }, + (error, data) => { + if (error) { + console.log('MKS:decryptSync error:'); + console.log(error); + kill = true; + } else { + decryptedInfo = data; + } + } + ); + + while (decryptedInfo === undefined && !kill) { + require('deasync').sleep(25); + } + if (!decryptedInfo) return encryptedString; + return decryptedInfo.Plaintext.toString(); +}; + +task("encrypt", "Encrypts credentials") + .setAction(async () => { + const answer = await inquirer.prompt([ + { + type: 'password', + message: 'Enter private key', + name: 'privateKey', + mask: '*', + } + ]); + const encryptedPrivateKey = await encrypt(answer.privateKey) + console.log('Encrypted credential, save this into your .env file:') + console.log(`PRIVATE_KEY=${encryptedPrivateKey}`); + }); + +module.exports = { + networks: { + hardhat: { + accounts: (!!process.env.PRIVATE_KEY && process.env.PRIVATE_KEY != '') ? [{ privateKey: decrypt(process.env.PRIVATE_KEY), balance: utils.parseEther('1').toString() }] : [] + } + }, + solidity: "0.7.3" +}; diff --git a/aws-encrypted-credentials/package.json b/aws-encrypted-credentials/package.json new file mode 100644 index 0000000..6276851 --- /dev/null +++ b/aws-encrypted-credentials/package.json @@ -0,0 +1,19 @@ +{ + "name": "aws-encrypted-credentials", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "devDependencies": { + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomiclabs/hardhat-waffle": "^2.0.0", + "chai": "^4.2.0", + "ethereum-waffle": "^3.0.0", + "ethers": "^5.0.0", + "hardhat": "^2.2.1" + }, + "dependencies": { + "aws-sdk": "2.1029.0", + "deasync": "0.1.24", + "inquirer": "8.2.0" + } +} diff --git a/aws-encrypted-credentials/scripts/sample-script.js b/aws-encrypted-credentials/scripts/sample-script.js new file mode 100644 index 0000000..1aa1a24 --- /dev/null +++ b/aws-encrypted-credentials/scripts/sample-script.js @@ -0,0 +1,32 @@ +// We require the Hardhat Runtime Environment explicitly here. This is optional +// but useful for running the script in a standalone fashion through `node