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.
- 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
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.
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
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
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
Copy the cloudfront url to /client/package.json/proxy
, so your local dev
environment knows where the remote backend is.
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.
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).
- 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
- this needs to be the function url of the
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
- "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"
- 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' }
- 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
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.
For Github, we need to create two separate OAuth apps, because each app
can only have one allwed callback url for the /idpresponse
.
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
- this is the function url for the
- Device flow: leave this disabled
- 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
{
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'
}
- 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
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
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"
}
}
{
"cognito": {
"region": "ap-southeast-2",
"email": {
"userPoolId": "ap-southeast-xxx",
"userPoolClientId": "xxx"
}
}
}
You can get these values from the Cognito UserPool.
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).
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.
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
- this will pick up the generated files from
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
).