Skip to content

Commit f64f667

Browse files
committed
Merge branch 'sst-master'
2 parents 0ce503f + f745273 commit f64f667

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+18285
-7656
lines changed

README.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
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).
66

7+
This repo is split into:
8+
9+
- **services**: [Serverless Framework](https://github.com/serverless/serverless) services
10+
- **infrastructure**: An [SST](https://github.com/serverless-stack/serverless-stack) app
11+
712
#### Steps
813

914
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.
@@ -16,26 +21,43 @@ To support the different chapters and steps of the tutorial; we use branches to
1621

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

19-
``` bash
24+
```bash
2025
$ npm install serverless -g
2126
```
2227

23-
Clone this repo and install the NPM packages.
28+
Clone this repo.
2429

25-
``` bash
30+
```bash
2631
$ git clone https://github.com/AnomalyInnovations/serverless-stack-demo-api
32+
```
33+
34+
Head over to the `infrastructure/` directory and install the npm packages.
35+
36+
``` bash
2737
$ npm install
2838
```
2939

30-
Run a single API on local.
40+
And build the SST app.
3141

3242
``` bash
43+
$ npx sst build
44+
```
45+
46+
Then deploy it to your AWS account
47+
48+
``` bash
49+
$ npx sst deploy
50+
```
51+
52+
Then head over to `services/notes/`. And run a single API endpoint locally.
53+
54+
```bash
3355
$ serverless invoke local --function list --path event.json
3456
```
3557

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

38-
``` json
60+
```json
3961
{
4062
"requestContext": {
4163
"authorizer": {
@@ -47,16 +69,16 @@ Where, `event.json` contains the request event info and looks something like thi
4769
}
4870
```
4971

50-
Finally, run this to deploy to your AWS account.
72+
Finally, run this to deploy to the API to your AWS account.
5173

52-
``` bash
74+
```bash
5375
$ serverless deploy
5476
```
5577

56-
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.
78+
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.
5779

5880
---
5981

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

62-
[Email]: mailto:[email protected]
84+
[email]: mailto:[email protected]

infrastructure/.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
6+
# testing
7+
/coverage
8+
9+
# production
10+
/build
11+
12+
# misc
13+
.DS_Store
14+
15+
# vim
16+
.*.sw*
17+
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*

infrastructure/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Getting Started with Serverless Stack Resources
2+
3+
This project was bootstrapped with [Create Serverless Stack](https://github.com/serverless-stack/serverless-stack).
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as iam from "@aws-cdk/aws-iam";
3+
import * as cognito from "@aws-cdk/aws-cognito";
4+
5+
export default class CognitoAuthRole extends cdk.Construct {
6+
// Public reference to the IAM role
7+
role;
8+
9+
constructor(scope, id, props) {
10+
super(scope, id);
11+
12+
const { identityPool } = props;
13+
14+
// IAM role used for authenticated users
15+
this.role = new iam.Role(this, "CognitoDefaultAuthenticatedRole", {
16+
assumedBy: new iam.FederatedPrincipal(
17+
"cognito-identity.amazonaws.com",
18+
{
19+
StringEquals: {
20+
"cognito-identity.amazonaws.com:aud": identityPool.ref,
21+
},
22+
"ForAnyValue:StringLike": {
23+
"cognito-identity.amazonaws.com:amr": "authenticated",
24+
},
25+
},
26+
"sts:AssumeRoleWithWebIdentity"
27+
),
28+
});
29+
this.role.addToPolicy(
30+
new iam.PolicyStatement({
31+
effect: iam.Effect.ALLOW,
32+
actions: [
33+
"mobileanalytics:PutEvents",
34+
"cognito-sync:*",
35+
"cognito-identity:*",
36+
],
37+
resources: ["*"],
38+
})
39+
);
40+
41+
new cognito.CfnIdentityPoolRoleAttachment(
42+
this,
43+
"IdentityPoolRoleAttachment",
44+
{
45+
identityPoolId: identityPool.ref,
46+
roles: { authenticated: this.role.roleArn },
47+
}
48+
);
49+
}
50+
}

infrastructure/lib/CognitoStack.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { CfnOutput } from "@aws-cdk/core";
2+
import * as iam from "@aws-cdk/aws-iam";
3+
import * as cognito from "@aws-cdk/aws-cognito";
4+
import * as sst from "@serverless-stack/resources";
5+
import CognitoAuthRole from "./CognitoAuthRole";
6+
7+
export default class CognitoStack extends sst.Stack {
8+
constructor(scope, id, props) {
9+
super(scope, id, props);
10+
11+
const { bucketArn } = props;
12+
13+
const app = this.node.root;
14+
15+
const userPool = new cognito.UserPool(this, "UserPool", {
16+
selfSignUpEnabled: true, // Allow users to sign up
17+
autoVerify: { email: true }, // Verify email addresses by sending a verification code
18+
signInAliases: { email: true }, // Set email as an alias
19+
});
20+
21+
const userPoolClient = new cognito.UserPoolClient(this, "UserPoolClient", {
22+
userPool,
23+
generateSecret: false, // Don't need to generate secret for web app running on browsers
24+
});
25+
26+
const identityPool = new cognito.CfnIdentityPool(this, "IdentityPool", {
27+
allowUnauthenticatedIdentities: false, // Don't allow unathenticated users
28+
cognitoIdentityProviders: [
29+
{
30+
clientId: userPoolClient.userPoolClientId,
31+
providerName: userPool.userPoolProviderName,
32+
},
33+
],
34+
});
35+
36+
const authenticatedRole = new CognitoAuthRole(this, "CognitoAuthRole", {
37+
identityPool,
38+
});
39+
40+
authenticatedRole.role.addToPolicy(
41+
// IAM policy granting users permission to a specific folder in the S3 bucket
42+
new iam.PolicyStatement({
43+
actions: ["s3:*"],
44+
effect: iam.Effect.ALLOW,
45+
resources: [
46+
bucketArn + "/private/${cognito-identity.amazonaws.com:sub}/*",
47+
],
48+
})
49+
);
50+
51+
// Export values
52+
new CfnOutput(this, "UserPoolId", {
53+
value: userPool.userPoolId,
54+
});
55+
new CfnOutput(this, "UserPoolClientId", {
56+
value: userPoolClient.userPoolClientId,
57+
});
58+
new CfnOutput(this, "IdentityPoolId", {
59+
value: identityPool.ref,
60+
});
61+
new CfnOutput(this, "AuthenticatedRoleName", {
62+
value: authenticatedRole.role.roleName,
63+
exportName: app.logicalPrefixedName("CognitoAuthRole"),
64+
});
65+
}
66+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { CfnOutput } from "@aws-cdk/core";
2+
import * as dynamodb from "@aws-cdk/aws-dynamodb";
3+
import * as sst from "@serverless-stack/resources";
4+
5+
export default class DynamoDBStack extends sst.Stack {
6+
constructor(scope, id, props) {
7+
super(scope, id, props);
8+
9+
const app = this.node.root;
10+
11+
const table = new dynamodb.Table(this, "Table", {
12+
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, // Use on-demand billing mode
13+
sortKey: { name: "noteId", type: dynamodb.AttributeType.STRING },
14+
partitionKey: { name: "userId", type: dynamodb.AttributeType.STRING },
15+
});
16+
17+
// Output values
18+
new CfnOutput(this, "TableName", {
19+
value: table.tableName,
20+
exportName: app.logicalPrefixedName("TableName"),
21+
});
22+
new CfnOutput(this, "TableArn", {
23+
value: table.tableArn,
24+
exportName: app.logicalPrefixedName("TableArn"),
25+
});
26+
}
27+
}

infrastructure/lib/S3Stack.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as s3 from "@aws-cdk/aws-s3";
3+
import * as sst from "@serverless-stack/resources";
4+
5+
export default class S3Stack extends sst.Stack {
6+
// Public reference to the S3 bucket
7+
bucket;
8+
9+
constructor(scope, id, props) {
10+
super(scope, id, props);
11+
12+
this.bucket = new s3.Bucket(this, "Uploads", {
13+
// Allow client side access to the bucket from a different domain
14+
cors: [
15+
{
16+
maxAge: 3000,
17+
allowedOrigins: ["*"],
18+
allowedHeaders: ["*"],
19+
allowedMethods: ["GET", "PUT", "POST", "DELETE", "HEAD"],
20+
},
21+
],
22+
});
23+
24+
// Export values
25+
new cdk.CfnOutput(this, "AttachmentsBucketName", {
26+
value: this.bucket.bucketName,
27+
});
28+
}
29+
}

infrastructure/lib/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import S3Stack from "./S3Stack";
2+
import CognitoStack from "./CognitoStack";
3+
import DynamoDBStack from "./DynamoDBStack";
4+
5+
// Add stacks
6+
export default function main(app) {
7+
new DynamoDBStack(app, "dynamodb");
8+
9+
const s3 = new S3Stack(app, "s3");
10+
11+
new CognitoStack(app, "cognito", { bucketArn: s3.bucket.bucketArn });
12+
}

0 commit comments

Comments
 (0)