Skip to content

Commit

Permalink
Merge branch 'sst-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
fwang committed Oct 8, 2020
2 parents 0ce503f + f745273 commit f64f667
Show file tree
Hide file tree
Showing 42 changed files with 18,285 additions and 7,656 deletions.
40 changes: 31 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

This repo is for the serverless backend API that we build over the course of the tutorial. You can find the repo for the frontend React app [here](https://github.com/AnomalyInnovations/serverless-stack-demo-client). And the repo for the tutorial [here](https://github.com/AnomalyInnovations/serverless-stack-com).

This repo is split into:

- **services**: [Serverless Framework](https://github.com/serverless/serverless) services
- **infrastructure**: An [SST](https://github.com/serverless-stack/serverless-stack) app

#### Steps

To support the different chapters and steps of the tutorial; we use branches to represent the project codebase at the various points. Here is an index of the various chapters and branches in order.
Expand All @@ -16,26 +21,43 @@ To support the different chapters and steps of the tutorial; we use branches to

To use this repo locally you need to have the [Serverless framework](https://serverless.com) installed.

``` bash
```bash
$ npm install serverless -g
```

Clone this repo and install the NPM packages.
Clone this repo.

``` bash
```bash
$ git clone https://github.com/AnomalyInnovations/serverless-stack-demo-api
```

Head over to the `infrastructure/` directory and install the npm packages.

``` bash
$ npm install
```

Run a single API on local.
And build the SST app.

``` bash
$ npx sst build
```

Then deploy it to your AWS account

``` bash
$ npx sst deploy
```

Then head over to `services/notes/`. And run a single API endpoint locally.

```bash
$ serverless invoke local --function list --path event.json
```

Where, `event.json` contains the request event info and looks something like this.

``` json
```json
{
"requestContext": {
"authorizer": {
Expand All @@ -47,16 +69,16 @@ Where, `event.json` contains the request event info and looks something like thi
}
```

Finally, run this to deploy to your AWS account.
Finally, run this to deploy to the API to your AWS account.

``` bash
```bash
$ serverless deploy
```

This project refers to an `.env` file for secret environment variables that are not checking in to the repo. Make sure to create one before dpeloying - https://serverless-stack.com/chapters/load-secrets-from-env.html.
The API service refers to an `.env` file for secret environment variables that are not checking in to the repo. Make sure to create one before deploying - https://serverless-stack.com/chapters/load-secrets-from-env.html.

---

This repo is maintained by [Anomaly Innovations](https://anoma.ly); makers of [Seed](https://seed.run) and [Serverless Stack](https://serverless-stack.com).

[Email]: mailto:[email protected]
[email]: mailto:[email protected]
20 changes: 20 additions & 0 deletions infrastructure/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build

# misc
.DS_Store

# vim
.*.sw*

npm-debug.log*
yarn-debug.log*
yarn-error.log*
3 changes: 3 additions & 0 deletions infrastructure/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Getting Started with Serverless Stack Resources

This project was bootstrapped with [Create Serverless Stack](https://github.com/serverless-stack/serverless-stack).
50 changes: 50 additions & 0 deletions infrastructure/lib/CognitoAuthRole.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as cdk from "@aws-cdk/core";
import * as iam from "@aws-cdk/aws-iam";
import * as cognito from "@aws-cdk/aws-cognito";

export default class CognitoAuthRole extends cdk.Construct {
// Public reference to the IAM role
role;

constructor(scope, id, props) {
super(scope, id);

const { identityPool } = props;

// IAM role used for authenticated users
this.role = new iam.Role(this, "CognitoDefaultAuthenticatedRole", {
assumedBy: new iam.FederatedPrincipal(
"cognito-identity.amazonaws.com",
{
StringEquals: {
"cognito-identity.amazonaws.com:aud": identityPool.ref,
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated",
},
},
"sts:AssumeRoleWithWebIdentity"
),
});
this.role.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*",
],
resources: ["*"],
})
);

new cognito.CfnIdentityPoolRoleAttachment(
this,
"IdentityPoolRoleAttachment",
{
identityPoolId: identityPool.ref,
roles: { authenticated: this.role.roleArn },
}
);
}
}
66 changes: 66 additions & 0 deletions infrastructure/lib/CognitoStack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { CfnOutput } from "@aws-cdk/core";
import * as iam from "@aws-cdk/aws-iam";
import * as cognito from "@aws-cdk/aws-cognito";
import * as sst from "@serverless-stack/resources";
import CognitoAuthRole from "./CognitoAuthRole";

export default class CognitoStack extends sst.Stack {
constructor(scope, id, props) {
super(scope, id, props);

const { bucketArn } = props;

const app = this.node.root;

const userPool = new cognito.UserPool(this, "UserPool", {
selfSignUpEnabled: true, // Allow users to sign up
autoVerify: { email: true }, // Verify email addresses by sending a verification code
signInAliases: { email: true }, // Set email as an alias
});

const userPoolClient = new cognito.UserPoolClient(this, "UserPoolClient", {
userPool,
generateSecret: false, // Don't need to generate secret for web app running on browsers
});

const identityPool = new cognito.CfnIdentityPool(this, "IdentityPool", {
allowUnauthenticatedIdentities: false, // Don't allow unathenticated users
cognitoIdentityProviders: [
{
clientId: userPoolClient.userPoolClientId,
providerName: userPool.userPoolProviderName,
},
],
});

const authenticatedRole = new CognitoAuthRole(this, "CognitoAuthRole", {
identityPool,
});

authenticatedRole.role.addToPolicy(
// IAM policy granting users permission to a specific folder in the S3 bucket
new iam.PolicyStatement({
actions: ["s3:*"],
effect: iam.Effect.ALLOW,
resources: [
bucketArn + "/private/${cognito-identity.amazonaws.com:sub}/*",
],
})
);

// Export values
new CfnOutput(this, "UserPoolId", {
value: userPool.userPoolId,
});
new CfnOutput(this, "UserPoolClientId", {
value: userPoolClient.userPoolClientId,
});
new CfnOutput(this, "IdentityPoolId", {
value: identityPool.ref,
});
new CfnOutput(this, "AuthenticatedRoleName", {
value: authenticatedRole.role.roleName,
exportName: app.logicalPrefixedName("CognitoAuthRole"),
});
}
}
27 changes: 27 additions & 0 deletions infrastructure/lib/DynamoDBStack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CfnOutput } from "@aws-cdk/core";
import * as dynamodb from "@aws-cdk/aws-dynamodb";
import * as sst from "@serverless-stack/resources";

export default class DynamoDBStack extends sst.Stack {
constructor(scope, id, props) {
super(scope, id, props);

const app = this.node.root;

const table = new dynamodb.Table(this, "Table", {
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, // Use on-demand billing mode
sortKey: { name: "noteId", type: dynamodb.AttributeType.STRING },
partitionKey: { name: "userId", type: dynamodb.AttributeType.STRING },
});

// Output values
new CfnOutput(this, "TableName", {
value: table.tableName,
exportName: app.logicalPrefixedName("TableName"),
});
new CfnOutput(this, "TableArn", {
value: table.tableArn,
exportName: app.logicalPrefixedName("TableArn"),
});
}
}
29 changes: 29 additions & 0 deletions infrastructure/lib/S3Stack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as cdk from "@aws-cdk/core";
import * as s3 from "@aws-cdk/aws-s3";
import * as sst from "@serverless-stack/resources";

export default class S3Stack extends sst.Stack {
// Public reference to the S3 bucket
bucket;

constructor(scope, id, props) {
super(scope, id, props);

this.bucket = new s3.Bucket(this, "Uploads", {
// Allow client side access to the bucket from a different domain
cors: [
{
maxAge: 3000,
allowedOrigins: ["*"],
allowedHeaders: ["*"],
allowedMethods: ["GET", "PUT", "POST", "DELETE", "HEAD"],
},
],
});

// Export values
new cdk.CfnOutput(this, "AttachmentsBucketName", {
value: this.bucket.bucketName,
});
}
}
12 changes: 12 additions & 0 deletions infrastructure/lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import S3Stack from "./S3Stack";
import CognitoStack from "./CognitoStack";
import DynamoDBStack from "./DynamoDBStack";

// Add stacks
export default function main(app) {
new DynamoDBStack(app, "dynamodb");

const s3 = new S3Stack(app, "s3");

new CognitoStack(app, "cognito", { bucketArn: s3.bucket.bucketArn });
}
Loading

0 comments on commit f64f667

Please sign in to comment.