Skip to content

Instantly share code, notes, and snippets.

@stevekinney
Last active September 9, 2023 18:55
Show Gist options
  • Star 99 You must be signed in to star a gist
  • Fork 43 You must be signed in to fork a gist
  • Save stevekinney/6ab02582829f039b6a14c973923909f8 to your computer and use it in GitHub Desktop.
Save stevekinney/6ab02582829f039b6a14c973923909f8 to your computer and use it in GitHub Desktop.

Frontend Masters: AWS for Frontend Engineers

You should have the following completed on your computer before the workshop:

  • Install the AWS CLI.
  • Have Node.js installed on your system. (Recommended: Use nvm.)
    • Install yarn with brew install yarn.
  • Create an AWS account. (This will require a valid credit card.)
  • Create a Travis CI account. (This should be as simple as logging in via GitHub).

Follow-Along Guides: I made a set of visual follow-along guides that you can reference throughout the course.

Repositories

  • Noted (Base): This is the base that you can clone and work with.
  • Noted (Live): This is the live version that I'm going to be working with.

Useful Links

S3 Bucket Policy

This might be helpful at some point.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME_HERE/*"
        }
    ]
}

Travis Configuration

language: node_js
node_js:
  - '8'
cache:
  yarn: true
  directories:
    - node_modules
script:
  - yarn test
before_deploy:
  - yarn global add travis-ci-cloudfront-invalidation
  - yarn run build
deploy:
  provider: s3
  access_key_id: $AWS_ACCESS_KEY_ID
  secret_access_key: $AWS_SECRET_ACCESS_KEY
  bucket: $S3_BUCKET
  skip_cleanup: true
  local-dir: dist
  on:
    branch: master
after_deploy:
  - travis-ci-cloudfront-invalidation -a $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -c $CLOUDFRONT_ID -i '/*' -b $TRAVIS_BRANCH -p $TRAVIS_PULL_REQUEST

Redirecting to index.html on Valid Client-side Routes

Viewer Request

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;

  console.log('Before', request.uri);

  if (/notes\/\d(\/edit)?/.test(request.uri)) {
    request.uri = '/index.html'
  }

  console.log('After', request.uri);

  callback(null, request);
};

Implementing Security Headers

Viewer Response

'use strict';

exports.handler = (event, context, callback) => {
  const response = event.Records[0].cf.response;

  response.headers['strict-transport-security'] = [{
    key: 'Strict-Transport-Security',
    value: 'max-age=31536000; includeSubDomains'
  }];

  response.headers['content-security-policy'] = [{
    key: 'Content-Security-Policy',
    value: "default-src 'self'"
  }];

  response.headers['x-xss-protection'] = [{
    key: 'X-XSS-Protection',
    value: '1; mode=block'
  }];

  response.headers['x-content-type-options'] = [{
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  }];

  response.headers['x-frame-options'] = [{
    key: 'X-Frame-Options',
    value: 'DENY'
  }];

  callback(null, response);
};

Implementing a Redirect

Origin Request

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;

  const response = {
    status: '302',
    statusDescription: 'Found',
    headers: {
      location: [{
        key: 'Location',
        value: 'https://bit.ly/very-secret'
      }],
    },
  };

  if (request.uri === '/secret') {
    console.log('Got it');
    return callback(null, response);
  }

  console.log('Nope');
  callback(null, request);
};
@stevekinney
Copy link
Author

They both accomplish the same thing. So, whatever is more appealing to you should work.

@krfong916
Copy link

krfong916 commented Feb 22, 2021

Hi Steve, how would you set CSP headers for this configuration (caching a static SPA), while using a 3rd party component library? Given that inline styles will be injected to the document at runtime and not at build time, from your view, how would one handle this? What would a meta tag look like?

I would most like to hear your thoughts. Thank you.

@JLowe-N
Copy link

JLowe-N commented Apr 7, 2022

I've got everything working except for the rickroll redirect from Origin Request.
I can see the 302/301 passthrough from Origin Request, but I can't seem to get the Location header to passthrough to bit.ly/very-secret.
It works if I change that header on Viewer Response (along with the security headers we did in a previous step).

This example seems to match AWS' example of Origin Request, with the only difference being that it is the same-origin domain relative route versus the absolute route to https://bit.ly/very-secret.

Just noticed V2 was also released, seems the obvious new things was the Cloudfront Functions and OAI (Cloudfront Only Access to S3).

Thanks for hosting these courses!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment