Skip to content

Latest commit

 

History

History
268 lines (223 loc) · 9.71 KB

running-own-infra.md

File metadata and controls

268 lines (223 loc) · 9.71 KB

Running your own infrastructure

If you're going to run your own infrastructure, it would be great to have feedback about anything that went or where the documentation could be improved.

Pre-requisites

  • Node/NPM available on the path
  • AWS account ID/alias
    • preferrably, you should use a "sub-account" to play with stuff like this
  • AWS Access key to run the CDK with
    • Never use the "root account" of an AWS account to do stuff, follow these instructions for creating an IAM account and access key

Configure AWS credentials

There's no CI/CD setup, soost people would run this project from a developer machine - in which case you'll needed set up credentials for the zinc profile.

Build the client app

  • cd <repo>/client
  • npm run build-prd
    • this will build the client web app suitable for deploying to CloudFront
    • we have to do this first, because the aws-infra project needs it to exist for the ClientBucketDeploymentStack to work

Bootstrap the AWS-CDK and do initial deployment

  • cd <repo>/aws-infra
  • npm run bootstrap
    • this will create an S3bucket and other resources that aws-cdk uses to manage deployments
  • npm run deploy
    • this will deploy all CDK stacks
    • note that the CloudFrontStack deploys files from dir <repo>/client/build that are generated by the client build, but since we haven't yet built the client, there won't be anthing in there at this point

Configure all the things

Once you've got the basic infrastructure deployed, you will know a lot of the info you need to configure things.

  • the cloudfront url
  • the function urls of the authn lambdas each of the lambdas

Configure your local dev proxy to know about cloudfront

Copy the cloudfront url to /client/package.json/proxy, so your local dev environment knows where the remote backend is.

Invoke the ZincApi lambda

Start the client locally, or curl the api at https://xxx.cloudfront.net/api-prd-v2/readConfig It will fail, if you look in the CloudWatch logs for the ZincApiLambda, it will log examples of what the config should look like for each Lambda that needs to be configured. Copy the example JSON from the logs into the Config SSM parameter values. Look at the sections below for how to populate real values.

Once you've gotten the configurations set to validly formatted values (even if only dummy values) - you should be able to hit the front page of zinc, but none of the sign-in methods will work until you've configured things correctly.

Configure Google authentication

Before you can authenticate with Google either via Cognito or directly, you need to use your own Google account to create OAuth credentials and configure the consent screen.

We only need one set of OAuth credentials and consent screen, because Google allows you to have multiplle callback urls (c.f. Github, where we need to create multiple OAuth clients).

Create the Google credentials

  • add one "authorized JS origins"
    • https://xxx.cloudfront.net
      • look in the AWS console under /Cloudfront/Distributions/Details
  • add two "authorized redirect URIs"
    • https://xxx.lambda-url.ap-southeast-2.on.aws/idpresponse
      • this needs to be the function url of the DirectGoogleAuthnApi lambda
    • https://xxx.auth.ap-southeast-2.amazoncognito.com/oauth2/idpresponse
      • this needs to be the Cognito domain for the google user pool
      • look in the AWS console under /Cognito/User pools/app integration for the domain, remember to make sure the url ends in /oauth2/idpresponse

Configure the Google consent screen

  • "App Domain"
    • https://xxx.cloudfront.net/
    • https://xxx.cloudfront.net/privacy
    • https://xxx.cloudfront.net/terms
    • may not need to do this, since we're only using non-sensitive scopes
  • "Authorized domains"
    • xxx.cloudfront.net
    • on.aws
      • top-level domain of all AWS function urls, which we use for the callback of the DirectGoogleAuthnApi
    • amazoncognito.com
      • top-level domain of all Cognito endpoints, which we use for the callback of Cognito Google authentication
  • "Scopes"
    • select non-sensitive scopes, for "email", "profile" and "openid"

Configure the DirectGoogleAuthnApi lambda

  • find the DirectGoogleAuthnApiConfig parameter
    • AWS console udner /AWS Systems Manager/ Parameter store
    • set the config:
    {
      clientId: 'from google dev console credentials',
      clientSecret: 'from google dev console credentials',
      allowedCallbackUrls: [ 'http://localhost:9090', 'https://xxx.cloudfront.net' ],
      // functionUrl of the DirectGoogleAuthnApi lambda
      functionUrl: 'https://xxx.lambda-url.ap-southeast-2.on.aws'
    }

Configure the Cognito-Google User pool with client details

  • AWS console under /Cognito/User Pools/Sign-in experience/Federated ID/Google
  • set the "Client ID" and "Client secret" from the values that google generated for your OAuth credentials

Configure the ZincApi lambda with Cognito-Google details

The ZincApi Lambda reads the DirectGoogle config straight from the config you already set up. For Cognito-Google integration, you need to set the cognito.google part to:

{
  "cognito": {
    "google": {
      "userPoolId": "ap-southeast-2_xxx",
      "userPoolClientId": "xxx",
      "userPoolDomain": "zinc-google-au"
    }
  }
}
  • userPoolId is displayed in the User pool overview
  • The userPoolClientId comes from the client in the "app integration" section

Once you've got all this stuff configured, you should be able to login to google via either the Cognito or Direct method. Make sure to do a hotswap-all to force the lambdas to re-read the updated config.

Configure Github authentication

For Github, we need to create two separate OAuth apps, because each app can only have one allwed callback url for the /idpresponse.

Create a "Zinc-Direct" OAuth App

In you Github account, look under /Settings/Developer Settings/OAuth Apps.

Make sure to take note of the client secret, because Github will never show it to you again.

  • Home page url: https://xxx.cloudfront.net/
  • Authorization callback URL: https://xxx.lambda-url.ap-southeast-2.on.aws/idpresponse
    • this is the function url for the DirectGithubAuthnApi lambda
  • Device flow: leave this disabled

Create a "Zinc-Cognito" OAuth App

  • Home page url: https://xxx.cloudfront.net/
  • Authorization callback URL: https://zinc-github-au.auth.ap-southeast-2.amazoncognito.com/oauth2/idpresponse
    • based on the Cognito USerPool "domain" in the "App integration" section
  • Device flow: leave this disabled

Configure Github-Direct lambda

{
  clientId: 'xxx',
  clientSecret: 'xxx',
  allowedCallbackUrls: [ 'http://localhost:9090', 'https://xxx.cloudfront.net' ],
  // functionUrl of the DirectGithubAuthnApi lambda
  functionUrl: 'https://xxx.lambda-url.ap-southeast-2.on.aws'
}

Configure the Cognito-Github integration

  • AWS console under /Cognito/User Pools/Sign-in experience/Federated ID/zinc-github-oidc
  • set the "Client ID" and "Client secret" from the values that Github generated for your OAuth App

Configure the ZincApi lambda with Cognito-Github details

The ZincApi Lambda reads the DirectGithub config straight from the config you already set up. For Cognito-Github integration, you need to set the cognito.github part to:

{
  "cognito": {
    "github": {
      "userPoolId": "ap-southeast-2_xxx",
      "userPoolClientId": "xxx",
      "userPoolDomain": "zinc-google-au"
    }
  }
}
  • userPoolId is displayed in the User pool overview
  • The userPoolClientId comes from the client in the "app integration" section

Configure the ZincApi lambda with Direct-Github details

The ZincApi Lambda needs some extra config related to the GithubOidc shim, so it can do authorization via HMAC (all the others use RSA).

For Direct-Github integration, you need to set the githubOidc part to:

{
  "githubOidc": {
    "clientSecret": "xxx",
    // function url of the CognitoGithubOidcApi lambds
    "functionUrl": "https://xxx.lambda-url.ap-southeast-2.on.aws"
  }
}

Configure ZincApi lambda with Cognito-email details

{
  "cognito": {
    "region": "ap-southeast-2",
    "email": {
      "userPoolId": "ap-southeast-xxx",
      "userPoolClientId": "xxx"
    }
  }
}

You can get these values from the Cognito UserPool.

Configure ZincApi lambda "authzSecrets"

This is the value used by the ZincApi lambda to generate and validate "accessToken" values.

You just need to set the authzSecrets array to have at least one valid secret (should be at least 20 chars long, I generate mine using Keepass to have at least 128 bits of entropy).

Bump the lambdas

Any time you change config in an SSM parameter without changing lambda code, you need to bump the lambdas because they only load their config in at startup and we need to force them to re-read. Run the /aws-client hotswap-all script, it will hotswap all lambd code, which results in a new version of the Lambda being created, which means the next lambda invocation will be a cold-start which will re-read the config.

TODO:STO add facebook and twitter instructions


Deploy the client app

  • cd <repo>/client
  • npm run build-prd
    • this will build the client web app suitable for deploying to CloudFront
  • cd <repo>/aws-infra
  • npm run deploy-cloudfront
    • this will pick up the generated files from <repo>/client/build, upload them to the S3 bucket and clear the CloudFront cache

That's it - you should now be able to navigate to the Cloudfront URL for the app and sign in (look in the CloudFront console under "Distribution domain name", there's also an "Output" for the CloudFront domain printed by deploy).