Use HashiCorp Terraform, AWS, Node, Webpack, and Vue to scaffold an example architecture for "internet of things" usage
- Note your AWS account ID (it should be a 12-digit number)
- Sign into the AWS console using the AWS account you just created
- This is your root AWS account
- Secure your root AWS account with Multi-Factor Authentication:
- Click your name in the header
- Click "Security Credentials"
- Follow the prompts to enable MFA and add an MFA device
- Create an AWS Identity and Access Management admin user for yourself on your root AWS account:
- Go to IAM
- Create a new user
- Enable "programmatic access" and "AWS Management Console" access for your new user
- Set a password for your new user
- Create an IAM group for your new user
1. Name the group (e.g.
admin) 1. Add theAdministratorAccessIAM policy to the group 1. Create the group, and add your user to the group - Finish creating your new IAM user
-
Copy your new IAM user's Access Key ID and Secret Access Key
-
Put your AWS Access Key ID and Secret Access Key in a file on your computer at
~/.aws/credentialsusing the following format:
# this file is located at ~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFor more information, see Configuring the AWS CLI
- Secure your new IAM user with Multi-Factor Authentication
- In IAM, click on the user name
- Click the "Security Credentials" tab
- Click the edit icon for "Assigned MFA device"
- Follow the instructions for adding a new MFA device
-
Sign out of your root AWS account
-
Sign back into the AWS console using your AWS account number, new IAM user, password, and MFA code
-
Install Node (version 10 or greater)
-
Install Git or GitHub Desktop (which installs Git by default)
-
Create a GitHub account (if you don't have one already)
-
Install the AWS Command Line Interface
- The easiest way to do this on macOS is with Homebrew
- First, install Homebrew on your Mac by running this command in Terminal:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - Then, install the AWS CLI by running this command:
brew install awscli
- First, install Homebrew on your Mac by running this command in Terminal:
- Clone this repo by running this command in Terminal:
git clone [email protected]:thegreatsunra/aws-terraform-iot.git-
Make a copy of
terraform/config.tf.exampleand name itconfig.tf -
Edit the values in the first section of
terraform/config.tfto match your own AWS Account ID, target AWS region, and your "company name"
- "Company name" is used in Cognito email templates for user account confirmations and messages
- If your computer has multiple AWS profiles configured in
~/.aws/credentials, change thedefaultvalue foraws_profileto the name of the profile you want to use - Change the value for
s3_web_appto the domain (and subdomain, if applicable) you want to use for hosting your web app- Note that this value must be unique, and cannot be the same as any other S3 bucket in the whole world
- Change the value for
s3_cloudtrailto a random (but recognizable by you) value that is unique, and will not be the same as any other S3 bucket in the whole world
- Don't touch the values for
authorizer_id,authorization, orcognito_app_client_idyet; we'll change those after we finish our first run of theterraform applyscript
-
Save your changes to
terraform/config.tf -
Open a Terminal window and navigate to your project's
terraformfolder -
At the command line, run this command to initialize your Terraform scripts and install all dependencies:
terraform init- Run this command to "plan" the execution of your Terraform scripts, and calculate how they will affect your AWS environment when applied:
terraform plan- Run this command to "apply" your Terraform scripts to your AWS environment, and reply
yeswhen prompted:
terraform applyYour architecture should now be deployed on your AWS account!
Now we have some manual work to do.
-
Copy the Authorizer ID value that is outputted by
terraform applyand replace the placeholderauthorizer_idvalue interraform/config.tfwith it -
In
terraform/config.tfchange theauthorizationvalue fromNONEtoCOGNITO_USER_POOLS -
Log in to the AWS Management Console using your IAM admin user, and make sure you are in the AWS region (e.g.
us-east-1) where Terraform deployed your architecture -
In the AWS Management Console, navigate to Cognito
-
Click to manage your User Pools
-
Click the User Pool created by Terraform
-
Under General Settings, click App Clients
-
Add a new App Client
-
Name your App Client
-
Uncheck "Generate client secret" (if "Generate client secret" is checked, your web app hosted on S3 will not work)
-
Create your new App Client, and copy its App Client ID
-
In
terraform/config.tfchange the placeholder value forcognito_app_client_idto your new App Client ID from Cognito -
At the command line, navigate to your project's
terraformfolder and runterraform plan -
Run
terraform applyand replyyeswhen prompted
Note to self: When I originally developed this architecture you couldn't create App Clients via Terraform. Whenever you run terraform apply now, however, Terraform deletes any App Clients that were created manually. This isn't desirable, of course, but it appears to be the reality until I isolate and fix the issue, likely by creating the App Client via Terraform rather than manually.
-
In the AWS Management Console, navigate to API Gateway
-
Choose the API Gateway created by Terraform (if you didn't rename it, it's probably called "Api")
-
Click Actions and click "Deploy API"
-
Choose "Prod" as your Deployment stage
-
Deploy your API
-
Copy the Invoke URL for your API (you'll add it to your web app later)
-
Access to your API should now be secured with Cognito
This step is necessary because there's a bug between Terraform and the AWS Management Console, where even though a Lambda function appears selected in the Triggers UI, it isn't.
-
In the AWS Management Console, navigate to Cognito
-
Open your User Pool
-
Go to Triggers, and change the Pre Sign-Up Lambda function to "None" (even if it's already set to "Cognito")
-
Scroll down and click "Save Changes"
-
Go back to Triggers, and change the Pre Sign-Up Lambda function back to Cognito
-
Scroll down and click "Save Changes"
-
When a user creates a new account, they will now "trigger" the "Cognito" Lambda function
-
Open a Terminal window, and navigate to the
gatewayfolder of this repo -
Run
npm installto install the Node dependencies for the Gateway -
Make a copy of
gateway/config.example.jsand name itconfig.js
-
Return to the AWS Management Console
-
Navigate to IoT Core
-
Click Manage and then click Register a Thing
-
Click "Create a Single Thing"
-
Give your Thing a name and click Next
-
Click Create Certificate
-
Download the certificate, public key, private key, and the "Root CA for AWS IoT" (four files in total) Note to self: the Root CA flow has changed, and now takes you to documentation that does a poor job explaining which of the four Root CA options you may want to download. You could probably do worse than use Amazon Root CA 1
-
Click Activate to activate your certificate (if you miss this step, it won't work!)
-
From your Thing's details screen, click Attach a Policy
-
Check the box next to the Policy that was created by Terraform (e.g. "thing")
-
Click Register Thing
-
Return to the AWS Management Console's AWS IoT home screen
-
Click Act
-
Click Create a Rule
-
Name your Rule (e.g. events)
-
For the Rule Query Statement, enter
SELECT * FROM 'events'seems to work) -
Click Add Action
-
Choose "Send a message to a Lambda function"
-
Click Configure Action
-
Choose your AWS IoT Lambda Function from the dropdown (i.e.
eventsunless you changed it in Terraform) -
Click Add Action
-
Review your Rule and click "Create Rule"
-
On your computer, rename the certificate files you downloaded from AWS IoT and put them in your local Gateway app's
gateway/certfolder. Refer to thegateway/cert/*.examplefiles for the proper naming convention -
Open
gateway/config.jsin your favorite text editor -
Replace the
xxxxxxxxvalues with your actual values from the AWS Management Console
- You can find your AWS IoT host URI on the "Settings" cog on AWS IoT portal main screen
-
Save your changes to
gateway/config.js -
At the command line, run
npm startto start your Gateway
-
Open a Terminal window, and navigate to the
appfolder of this repo -
Run
npm installto install the Node dependencies for the app -
Make a copy of
app/.env.exampleand name it.env(.env.exampleis a dotfile so it might be hidden by default on your computer) -
Open
app/.envin a text editor -
Replace the
xxxxxxxxxxxxvalues with your actual values from AWS
- If you "edit" your Cognito Identity Pool, you can copy its ID from the AWS Management Console
-
Save your changes to
app/.env -
At the command line, run
npm run serveto start the app -
The local development server for the app should start and automatically launch the app at http://localhost:9000 in your default web browser
-
Create a new user account and password in your app's web UI (or log in with your existing Cognito credentials if you already have them)
- By default, the Cognito Pre Sign-Up Trigger Lambda function requires that all users creating a new account use an email address with
@gmail.comas the domain
-
Open your email, copy the verification code you received from Cognito, and submit it in your app's web UI
-
Finally, log into your app with the username and password you provided
-
The app should show incoming data from your Gateway
- If the app doesn't work, make sure your
.envvariables are set correctly - If you do change your
.envvariables, stop and start the dev server to make sure your changes are applied
Note: The npm run deploy script requires you have the AWS CLI installed and the proper credentials configured on your computer to access your AWS S3 bucket.
-
From your web app's root folder, run
npm run buildto generate a distribution version of your app -
Edit
app/package.jsonand change the URL values in thedeployscript to match the location of your own AWS S3 bucket you created with Terraform -
Save your changes to
app/package.json -
At the command line, navigate to the
appfolder of this repo and runnpm deployto use the AWS CLI to upload your app to S3 -
Test your app at your S3 URL and make sure it works