Run a steem-js bot as AWS Lambda function
utopian-io·@nafestw·
0.000 HBDRun a steem-js bot as AWS Lambda function
#### What Will I Learn? In this tutorial - You will learn to embed a steem-js bot into an AWS Lambda - You will learn to configure an AWS Lambda to be triggered periodically - You will learn to protect your Steem key with KMS #### Requirements To follow this tutorial you need - node.js installed - an Amazon AWS account - AWS CLI installed and configured for your account #### Difficulty Intermediate #### Tutorial Contents This tutorial will show how to create a steem-js bot, that runs as AWS Lambda. The bot will be triggered periodically. Further this tutorial will show how you encrypt your Steem key with KMS, such that it is not necessary to include it as plain text in the bot's source code. ##### What is AWS Lambda? > AWS Lambda is a compute service that lets you run code without provisioning or managing servers. AWS Lambda executes your code only when needed and scales automatically, from a few requests per day to thousands per second. (from the [AWS Documentation](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)) ##### Why AWS Lambda? AWS Lambda functions are the only AWS service that offers a free contingent, even after the first 12 months (where Amazon offers a limited set of its AWS services for free). Every month up to one million Lambda calls are included with up to 400.000 GB/s per month. The second metric is a bit confusing, basically it it means that the overall runtime of your Lambda multiplied with its memory consumption must be less than 400.000 GB/s per month to stay within the free contingent. The lowest available memory tier is 128 MB. This is sufficient for a typical steem-js bot, such that it may run up to 3.2 million seconds per month. Hence if one execution of a bot run takes less about 3 seconds we are bound by the one million free calls per month, such that the bot may run more than 1000 times per hour, which should be totally sufficient for most applications. Long story short, you don't need to pay for a dedicated server, if you run your bot as AWS Lambda function. ##### Project setup Setup a new node project and add steem-js as dependency with npm init npm install steem --save-dev Be sure to select `index.js` as main entry point. I separate the project into three source files: `bot.js` that includes all the logic for the bot, `index.js`with the extra logic for the AWS Lambda, and `app.js` to test the bot locally.  ##### Implementation of the bot The bot itself is pretty simple, as this is not the main focus of the tutorial. It's purpose is to look for new posts in `utopian-io` and to vote for the first tutorial it finds. The key required for the vote is passed as parameter to the bot function, while other settings are directly configurable in `bot.js`. The full source code of `bot.js` is shown below. ```` "use strict"; const steem = require("steem"); /* settings */ var my_account = "nafestw"; var vote_weight = 10000; module.exports = function(wif) { steem.api.getDiscussionsByCreated( { tag: "utopian-io", limit: 100 }, (err, result) => { // filter everything but tutorials let candidates = result.filter(res => { if (!res.json_metadata) return false; return res.json_metadata.indexOf('"type":"tutorial') !== -1; }); if (candidates.length > 0) { let target = candidates[0]; // vote for the first one steem.broadcast.vote( wif, my_account, target.author, target.permlink, vote_weight, function(err, result) { if (err) console.log(err); else console.log(result); } ); } } ); }; ```` The implementation of app.js is trivial and just calls the function exported by `bot.js` with the Steem key: ```` "use strict"; const bot = require("./bot"); var wif = "ENTER_STEEM_KEY_HERE"; bot(wif); ```` ##### Encryption of the Steem key As state above, it is not a good practice to include your key in plain text in source code that is uploaded to a server. AWS provides an encryption mechanisms to solve this, such that an encrypted version of the key can be stored with the Lambda function.  ###### Create a Role Log into the AWS Management console and select IAM under "Security, Identity & Compliance". First you need to setup a role. This role will be needed for the key and to create the Lambda function: * Select Roles -> Create Role. * Select Lambda and press Next * Select AWSLambdaBasicExecutionRole and press Next * Enter a name for the role: steem_bot_role ###### Create the encryption key On the left, select the last point: "Encryption Keys". Now it's necessary to select the region, which will also be the region you will use for your Lambda later. You can find all regions that support Lambdas [here](https://aws.amazon.com/de/about-aws/global-infrastructure/regional-product-services/). Next, select "Create Key", enter an alias for the key and select next step. Adding tags is optional and can be skipped by selecting "Next Step". Next select the users that may administer the new key. Now, for the usage permissions, select the role created before. Review your settings and press Finish. The next page shows the Key ID required for encryption in the next step. The encrypt your Steem key, go to the command line and encrypt your key with aws kms encrypt --key-id <kms_key_id> --plaintext "<YOUR_STEEM_KEY>" --query CiphertextBlob --output text | base64 -D > encrypted_secret Replace `<kms_key_id>` with the key id from the AWS management console and `<YOUR_STEEM_KEY>` with your Steem key. The `aws kms encrypt` command outputs the encrpyted string in base64 encoding. To decrypt it, it must be in binary form. Hence it is piped to `base64 -D` and written to the file `encrypted_secret` which should be stored next to the bot's source code. ##### Call the bot function from the Lambda handler Using AWS Lambdas to execute your code requires that it is encapsulated in a handler function. This function must be exported to `exports.handler` and receives three parameters `(event, context, callback)`, which we ignore, because we don't need them. On default AWS Lambda expects `export.handler` to be defined in `index.js` (you can change that in the AWS management console). The encrypted key is loaded from file and decrypted with kms.decrypt before it is passed to the bot function. The full implementation of `index.js` is: ```` "use strict"; const bot = require("./bot"); var fs = require("fs"); var AWS = require("aws-sdk"); var kms = new AWS.KMS({ region: "us-west-2" }); var secretPath = "./encrypted_secret"; var encryptedSecret = fs.readFileSync(secretPath); var params = { CiphertextBlob: encryptedSecret }; exports.handler = (event, context, callback) => { kms.decrypt(params, function(err, data) { if (err) console.log(err, err.stack); else { let wif = data["Plaintext"].toString(); bot(wif); } }); }; ```` ##### Deploy the Lambda To deploy the Lambda, all code and assets (as encrypted_secret) including the node_modules folder must be added to a ZIP file. (Smaller Lambdas without extra dependencies can be edited online). If you have the ZIP file ready, go to the AWS Management Console and select Lambda and then Create function. In the following form keep "Author from scratch" selected, enter a name for the function, keep the NodeJS Runtime, and choose the `steem_bot_role` that has been created before. Then press "Create Function".  In the section "Function code", select "Upload .ZIP file" as "Code Entry Type", press "Upload" and select the ZIP file with your bot's code.  Finally, it is necessary to add a trigger for the Lambda function. The steem_bot should be triggered periodically, so select CloudWatch Events and "Create New rule" for a new rule. The rule must be named and a expression for the actual schedule must be specified. The simplest rules are in the form `rate(5 minutes)`, which runs the Lambda function every five minutes. If everything is entered, press Add.  Amazon AWS Lambdas are terminated after a configurable timeout, which is three seconds on default. Depending on what your bot does, you may need to adapt this setting. You can find it on the lamba's page further below under "Basic Settings". That's it. If you press Save on the top right, the ZIP file is uploaded and your Lambda is saved. You can test it immediately by selecting "Test" or just wait for its first automatic invocation. If something doesn't work as expected, you can extend your Lambda's code with `console.log()` statements, which are accessible through the monitoring functions of AWS Lambda. This concludes the tutorial on running a steem-js bot as AWS Lambda function. <br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@nafestw/run-a-steem-js-bot-as-aws-lambda-function">Utopian.io - Rewarding Open Source Contributors</a></em><hr/>