Werner Digital

Technology

AWS Amplify and Gatsby

Build and host high performance serverless web apps for cheap with AWS Amplify and the free tier.

Gatsbyjs is a Jamstack implementation that can use AWS Amplify hosting directly. (see our Gatsby page for more information on upgrades and gatsby integrations)

Running Gatsby with AWS Amplify is very inexpensive, and integrates well with public Git providers to provide a slick development pipeline and easy access to a wide variety of AWS services. The final application uses a CDN to scale and runs very efficiently, it is hard to beat on general lighthouse performance tests.

Contents

Tech Overview

It's hard not to like the combination of AWS Amplify with a static site generator like Gatsby. Gatsby features include:

  • Blazing performance (90-100 lighthouse) and scale

  • Good security, and low attack surface

  • Serverless, component based development

  • supports Typescript

  • progressive web app support

  • Solid testing foundation with jest and testing-library

  • (more tech Gatsby info here)

  • Lightweight, inexpensive, and even fits well on the AWS free tier

  • scaleable authentication

  • Quick API access to most AWS services

  • Dynamic data access via GraphQL, API gateway, etc

  • Automated CI/CD build

Progressive web apps are designed to be installed so that they can run mostly off-line.

Note: You can also host Gatsby projects directly on AWS S3 and Cloudfront, described well here on Joshua Walsh's Blog. (ignore the title, I like my way better)

Install

You will need to have node and the node package manager (npm) installed.

Requirements

  • node -v (at least 14.x (up from 12.x in Gatsby v3)

  • npm -v (at least 6.x)

  • Use the latest gatsby cli install documentation.

  • amplify install doc

  • npm i -g @aws-amplify/cli (7.6.5 -> 9.2.1?)

create necessary IAM user for your workstation

  • amplify configure

Project Setup

The basic steps for each project:

  • gatsby new <proj-name> https://github.com/account/starter-name
  • amplify init
  • amplify push (creates resourceless proj)
  • Using public git for ci/cd
    • git init (or git remote add with commit and push)
    • connect frontend via amplify console
  • little tweaks

Gatsby (or other framework setup)

For more information, please see the WD gatsby page

amplify init

Note: It is recommended to run this command
from the root of your app directory
? Enter a name for the project nutin
The following configuration will be applied:

Project information
| Name: nutin
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: build
| Build Command: npm.cmd run-script build
| Start Command: npm.cmd run-script start

? Initialize the project with the above
configuration? (Y/n) n
? Enter a name for the environment prod
? Choose your default editor: None
? Choose the type of app that you're building
javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path:  src
? Distribution Directory Path: build
? Build Command:  npm.cmd run-script build
? Start Command: npm.cmd run-script start
Using default provider  awscloudformation

? Select the authentication method you want
to use: AWS profile

? Please choose the profile you want to use
amplify-dev

Your project has been successfully initialized
and connected to the cloud!

git init

  • on github create new repo (private) unpopulated

inside the project directory

  • git remote add origin git@github.com:username/reponame.git

  • git branch -M main

  • git push -u origin main

  • git switch -c next

  • git push -u origin next

  • on github allow amplify permission to repo

    • goto settings, applications, aws amplify
    • select repositories, add to list and save

connect frontends

goto the amplify console on aws

  • connect to github, specify repo and branch
  • select prod environment, enable ci/cd
  • if you don't have an amplifyconsole-backend-role, create it
  • build and test settings are standard
  • if you want to autogenerate an aws-export.js for every build, make sure you disable full ci/cd. (this is also discussed in the using libraries section )
  • (amplify backend on new?)

add domains

  • enter root domain
  • exclude root (unless this is your main domain site)
  • change subdomain to intended target

little tweaks

The 404 page needs the following entry in rewrites:

  • /<*> => /404.html as a 404 rewrite

Using AWS Features

Amplify adds AWS features by setting up cloudformation files to build specific roles and services, and then saving the references to them off into a file named src/aws-exports.js. Categories (as of March 2022) include:

  • notifications
  • api
  • auth
  • custom
  • storage
  • analytics
  • function
  • geo
  • hosting
  • interactions
  • predictions
  • xr

Since th aws-export.js file is generated from the Amplify settings, it is excluded from the git repository management and needs to be regenerated before the build step with an amplify pull command. (or follow the instructions to autogenerate aws-exports.js

The information in the aws-export isn't necessarily confidential, but can contain information about the specific AWS id's of internal/external associated custom services, such as GraphQL/REST API id's, Cognito pool and web client id, etc. This restricts the ability to use lightly secured (hardcoded apikey) or hidden unsecured resources, but this is a bad practice anyway.

basic gatsby config

  • add the following into gatsby-browser.js
import Amplify, { API, graphqlOperation } from "aws-amplify";
import awsConfig from "./src/aws-exports";
Amplify.configure(awsConfig)

customizing aws-exports.js

A side-effect of aws-exports.js being generated, by amplify is that you cannot customize it via editing the file. You may also have issues using the full stack ci/cd on workstations that haven't performed the amplify push to generate the file for local development.

Creating a aws-safeset.js avoids this issue, but bypasses the front/backend linkage on the Amplify console configuration. It also requires that this file be included into the git repository for auto ci/cd uses. It also may introduce dependencies on certain aws amplify or ui versions, as later versions may change the awsmobile json structure.

securing values

To make management (and privacy) of amplify values, (or to include other more private api keys) place the actual values in an environment variable accessible to the build phase and refer to them in the file via

authentication hack for api, graphql

import { Auth } from "aws-amplify"

// this function allows API (and graphQL API) access to
// extended user identity information via authentication header
const getIdToken = async () => ({
  Authorization: (await Auth.currentSession()).getIdToken().getJwtToken()
});

  • custom_header: getIdToken, (API gateway secured via cognito)
  • "graphql_headers": getIdToken, (GraphQL API secured via cognito)

AWS Feature Details

add amplify auth

This amplify feature provides access to AWS Cognito integration. This can be used for website authentication, and authenticating to public API's. Cognito can also be used for authorization by using a variety of IAM controls, groups, and attribute methods.

auth/unauth

One of the simpler forms of using Cognito is with member only webapps. Any attempt to access any page should lead to a password prompt, with only successful signons showing a page. IAM privileges can be assigned but this is primarily application enforced. Backend API should all be secured via returned cognito encrpyted tokens passed in headers.

auth/unauth w/ groups

To allow for subsection security, a group setup can be used to add IAM or application privileges.

auth w/ tenant

Grouping authenticated users into tenant groups can be done securely by specifying the tenant id in a userpool attribute. This attribute can be retrieved securely from jwt tokens by API and applications to filter content.

CI/CD with git

Amplify has an easy CI/CD setup driven by public Git repositories such as Github or Bitbucket. There are some extended security considerations (as with all DevOPS automation) but the built-in automation is useful for a wide range of users, from solo coders to large teams.

manually connecting branches

Easily add branches on the console app page with the connect branch button. Connected branches are managed on the app settings general page, under branches.

main branch with prod backend

The simplest Git branching workflow is to define a prod backend, and then build whenever the default branches is updated. Some basic security suggestions:

  • default branch should be protected to pull requests only w/ approval
  • disable full stack ci/cd for teams (front-end only)

next branch connection

Adding a next branch automation is a nice way to integrate and test builds independently if the production version on the default branch

  • common when main build should be up 24x7
  • good place to have automated testing/lint checks
  • easy to place a quick site password for a little dev privacy
  • allows for using test resources during build phase, such as testdb or dummy users.

feature branches

To keep track of major changes, or when multiple developers are working on closely related code, it is a good idea to use a full feature branch workflow, integrating the feature branches back into next branch when ready.

  • rarely should these be auto built, mostly run local

pull request previews

This is handy on main branches that have no next branch for integration, as it automatically builds versions based on the pull request branch. This feature should only be used on private repositories, otherwise anyone could allow unrestricted access to backends by simply creating a pull request with hostile code.

  • available under previews on app settings
  • sets up pull request check on creation
  • view via console under frontend/branch/previews
  • also shows in pull request with URL
  • tears down preview when pull request closes

branch auto-detection

This would be handy in a few cases

  • bespoke production instances
  • pre-qualify branch builds before integration

This is managed on the app settings general page, under app details.

Raw Notes

  • change default build to
  • add node v14 requirement
  • amplify domain
  • identity pool fix

backend dev

add amplify features

  • npm add aws-amplify @aws-amplify/ui-react