AWS Lambda & Serverless Architecture Bootcamp (Build 5 Apps) - Tutorial from Riyaz Sayyad (Udemy)
node app.js
node app
node
-> > you can run js
npm init
node index
npm install underscore --save
npm init
npm install express --save
node server
npm install body-parser --save
aws sts get-caller-identity
npm init
npm install moment --save
- image-magick-lambda-layer
- Deploy
- Copy Layer ARN
- Lambda console ->
node-resize-image-stack-ResizeImageFunction-dR...
- Layers -> Add a Layer -> Specify an ARN -> Paste Layer ARN -> Add
- www.test-cors.org
- Test
https://b3fsn6f2oc.execute-api.eu-north-1.amazonaws.com/Prod/greet/Arina
Fired XHR event: error
- Dev Tools (
Ctrl+Shift+I
)Access to XMLHttpRequest at 'https://b3fsn6f2oc.execute-api.eu-north-1.amazonaws.com/Prod/greet/Arina' from origin 'https://www.test-cors.org' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- Enable CORS Manually
- API Gateway Console
GET -> Add Response 200 -> Add Header -> Access-Control-Allow-Origin(can not do this)- for Lambda proxy integration must provide in Lambda
- Test in www.test-cors.org -> OK
- Create IAM Role for API Gateway to Log
- IAM Console -> New Role ->
- Select your use case:
API Gateway
-> - Permissions:
AmazonAPIGatewayPushToCloudWatchLogs
(default) - Role name:
riyaz-apigateway-logs-role
- Attach role to the Gateway
- API Gateway console -> Settings
- CloudWatch log role ARN: paste ARN (like
arn:aws:iam::392971033516:role/riyaz-apigateway-logs-role
)
- Enable Logs for API Gateway
- Stages -> Prod -> Logs/Tracing
- Enable CloudWatch Logs
- Log level: INFO
- Log full requests/responses data:
true
- Enable Detailed CloudWatch Metrics:
true
- Invoke endpoint
- POST {{serverUrl}}/math/multiply (for example)
- View Logs in CloudWatch
API-Gateway-Execution-Logs_{rest-api-id}/{stage_name}
API-Gateway-Execution-Logs_gavlhwnjj1/Prod
- API Console -> Resources ->
math/{operation}
-> POST ->- Actions -> Edit Method Documentation
- Documentation -> Publish Documentation
- Stage: Prod
- Version: 1.0
- Export
- OpenAPI 3 + API Gateway Extensions
- Create API Key
- API Gateway Console -> API Keys ->
- Actions -> Create API Key
- Name:
Dev team
- Description:
API Key for development team
- Create Usage Plan
- API Gateway Console -> Usage Plans
- Name:
PremiumUsagePlan
- Description:
Usage Plan for Premium Users
- Rate:
1000
requests per second - Burst:
200
- Quota:
1000000
req per month - Associated API Stages -> Add API Stage ->
- Greeting API -> Prod
- Add API Key to Usage Plan -> Dev team
- API Console ->
greet/{name}
-> GET -> Method Execution ->- API Key Required -> true
- same for the POST
- HTTP Request
- Add header
- x-api-key: {{apiKey}}
- DynamoDB Console
- Create Table
- Table name:
td_notes
- Primary key:
- Partition key:
user_id
String - Sort key:
timestamp
Number
- Partition key:
- Customize Settings
- Secondary indexes
- New Local Secondary Index
- Sort key:
title
String - Index name:
title-index
- Attribute projections:
All
- Sort key:
- New Local Secondary Index
- Sort key:
cat
String - Index name:
category-index
- Attribute projections:
All
- Sort key:
- New Global Index
- Partition key:
note_id
String - Sort key: no
- Index name: note_id-index
- Attribute projections:
All
- Partition key:
- New Local Secondary Index
- Capacity
- Autoscaling: OFF
- RCU: 2 (for study)
- WCU: 2 (for study)
- Create table
- Table name:
- Create Item
- DynamoDB Console -> td_notes -> Create item
- user_id: random String (I prefer UUID generator)
- timestamp: random number (I prefer unixtimestamp)
- note_id: some UUID
- cat:
"general"
- title:
"my note"
- user_name:
"Art"
- content:
"this it the content of my note"
- Duplicate
- Duplicate and modify
- Repeat a couple of times
- Create item without note_id
- Create item without cat
- Scan
- through
category-index
(local sec index) -> withoutcat
are absent - through
note_id-index
(global sec index) -> withoutnote_id
are absent
- Two Options
- Scan
- Query
- Query by primary key
- partition key + sort key (Number)
- equal, less, greater, between
- sort asc/desc
- or
- just partition key
- Query by local secondary index
- partition key + sort key (String)
- equal, less, greater, between, Begins with
- Query by global secondary index
- by partition key (note_id)
- Filter
- using non index keys
- applied after query is performed
- so it NOT affect your RCU using operations
- Example
- Query table by user_id = 1289c03b-77f6-4c7a-b5d3-0def67643a58 skipping sort key filtering:
- content (String) contains
note 3
- Scan
- scan operations across partitions
npm init
npm install aws-sdk --save
npm install async underscore --save
- test function -> result
{
"key1": "value1",
"key2": "value2",
"key3": "value3",
"lambdaFunction": "event-logging-function",
"lambdaVersion": "$LATEST"
}
- Publish new Version
- Actions -> Publish new Version
- Description: v1
- View ->
arn:aws:lambda:eu-north-1:392971033516:function:event-logging-function:1
1
- is version number- Test
{
"key1": "value1",
"key2": "value2",
"key3": "value3",
"lambdaFunction": "event-logging-function",
"lambdaVersion": "1"
}
- Modify code:
Code and handler editing is only available on the unpublished function page.
Edit code
or switch to the$LATEST
- Add comment, Deploy
- Publish new version
- API Gateway -> Greeting API ->
- create Resource:
/lambda
- create Method: GET
- Lambda
arn:aws:lambda:eu-north-1:392971033516:function:event-logging-function
- Test -> got result with Lambda version
$LATEST
- create Resource:
- Using versioned Lambda
- API Gateway ->
/lambda
-> GET -> Lambda function event-logging-function:1
- Deploy
- Test -> got result with Lambda version
1
- Ones again for version 2
- API Gateway ->
- Workflow without aliases
- modify lambda code
- publish new version
- api gateway console
- integration request
- modify used lambda version
- give the necessary IAM permissions
- deploy API
- Lambda Console -> Create alias
- Name:
prod
- Description:
Alias for Prod Stage
- Version:
3
- Create
- Name:
- Create another alias
- Name:
test
- Version:
$LATEST
- Name:
- Use Version Alias in API Gateway
/lambda
-> GET -> Lambda Function ->event-logging-function:test
- Test -> got result with Lambda version
$LATEST
- Update Lambda
- Deploy new Version
- Point alias test to new version
- no need to redeploy API Gateway
- Test:
"lambdaVersion": "4"
- Stages:
- Test
- Prod
- Add Stage variable
- eventLoggerAlias
- for Test Stage:
test
- for Prod Stage:
prod
- for Test Stage:
- eventLoggerAlias
- Provide Lambda alias through Stage variable
- Resources ->
/lambda
-> GET -> Int.Request -> Lambda Function event-logging-function:${stageVariables.eventLoggerAlias}
- Add Permission to Lambda Function
- Warning message with command
aws lambda add-permission --function-name "arn:aws:lambda:eu-north-1:392971033516:function:event-logging-function:${stageVariables.eventLoggerAlias}" --source-arn "arn:aws:execute-api:eu-north-1:392971033516:7apx5c3x79/*/GET/lambda" --principal apigateway.amazonaws.com --statement-id 5f811966-4bd1-4fe6-babc-8ef656f8b3ab --action lambda:InvokeFunction
- Run this command for each stage alias
- Resources ->
- Deploy API
- Deploy Test Stage
- Deploy Prod Stage
- Test
- Lambda -> Functions -> event-logging-function -> Alias: prod
- General Configuration -> Edit
- Version: 3
- Weighted Alias
- Additional version: 4
- Weight: 10% (for study purpose 40%)
- Save
- Invoke several times
Section5-DeepDive\requests.http
- Move to 100%
- API Gateway -> Stages -> Prod -> Canary -> Create Canary
- Percentage of requests directed to Canary: 50
- Resources ->
/lambda
-> GET -> Integration Request- Mapping Template
{
"stage":"$context.stage",
"timestamp": "$context.requestTime"
}
- Deploy to Prod (Canary enabled)
- Invoke several times
Section5-DeepDive\requests.http
- 50/50 w/wo timestamp
- Promote Canary
- Delete Canary
- Lambda Console
event-logging-function
- Configuration
- Environment variables -> Edit -> Add
APP_NAME
:My App
APP_SECRET
:SUPER_SECRET_PASSWORD
- Save
- Test through console
- Lambda console
- Edit Environment variables
- Enable helpers for encryption in transit
- Need to create KMS key (user managed)
- KMS -> Customer Managed Keys -> Create key
- Symmetric
- Alias: LambdaCustom
- Description: Lambda Custom KMS Key
- Define key administrative permissions: art_admin, art_mfa
- Define key usage permissions: art_admin, event-logging-function-role-l6gd2i7g
- Create
- Lambda console
- Edit Environment variables
- AWS KMS key to encrypt at rest
- Use a customer master key:
LambdaCustom
- Use a customer master key:
- Enable helpers for encryption in transit
- Encrypt
APP_SECRET
- Decription Code Snippet
- AWS KMS key to encrypt at rest
- Test in console -> OK
- Lambda function:
getRandomMessage
- edit VPC
- attach this function to the default VPC
- Security group:
- Default VPC security group
- Need to create role with permission to access to VPC
- IAM
- Create custom role:
- Use case:
Lambda
- Attach permissions policies:
AWSLambdaVPCAccessExecutionRole
- Role name:
lambda_vpc
- Use case:
- Create custom role:
- Lambda console
- Attach role
lambda_vpc
to the Lambda - edit VPC
- attach this function to the default VPC
- Security group:
- Default VPC security group
- Attach role
- Test lambda in the console
- SNS console
dlq-test-LambdaAsyncTrigger-VWHYXUTS4W2S
- Publish message:
Triggering Lambda function dlqTest
- Lambda CloudWatch Logs
- Error
- Retry in 60 sec
- Another retry in ~120 sec
- SQS console
- Poll for messages
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:eu-north-1:392971033516:dlq-test-LambdaAsyncTrigger-VWHYXUTS4W2S:6b87912b-920f-4050-bd3d-7861a7181ec5",
"Sns": {
"Type": "Notification",
"MessageId": "71ce0149-086e-531e-b7c8-5b2b3e2baf26",
"TopicArn": "arn:aws:sns:eu-north-1:392971033516:dlq-test-LambdaAsyncTrigger-VWHYXUTS4W2S",
"Subject": null,
"Message": "Triggering Lambda function dlqTest",
"Timestamp": "2022-01-19T15:53:41.924Z",
"SignatureVersion": "1",
"Signature": "KPdHd2fRJYjgNTOyc2P1m7l4DA7KV5/G8uBezLJLePgyYMNJBEjIsx+aM5D/e1vGor2nmYSIvysBR5uOMpZzejbDDcKCb86V3WXdQIv0EOMu9NGIpPRu7QJzQAWGnPmaFA0jP2jV14B8SBK1HPxEgyngYApcLDAG9D6DK0d6uFLsgoQt/MEMwev5TbfEoRA63iR397Zh0N11zWm7+bLPPY095GDI3teodyVXlA1ORZ/0+tqCn3X2df6LOvqCa7mG5JDfc9FONzrzEWSnv42614LrhauOcYurBKE0iPj7Lw9perR8i+gWHtN4/tywQFwpFtJVBvDStyQdqLTAiFxAEA==",
"SigningCertUrl": "https://sns.eu-north-1.amazonaws.com/SimpleNotificationService-7ff5318490ec183fbaddaa2a969abfda.pem",
"UnsubscribeUrl": "https://sns.eu-north-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-north-1:392971033516:dlq-test-LambdaAsyncTrigger-VWHYXUTS4W2S:6b87912b-920f-4050-bd3d-7861a7181ec5",
"MessageAttributes": {}
}
}
]
}
Create user for testing
- IAM -> Users
- Add users
- Name:
apigw-user
Access key - Programmatic access
- Name:
- Create user (wo permissions)
- Access key ID:
AKIAVW7XGDOWFLXUJMBT
- Secret access key:
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
- Access key ID:
- Add users
- Add permissions
- User
apigw-user
- Add inline policy
- Service: ExecuteAPI
- Actions: Invoke
- Resources:
arn:aws:execute-api:eu-north-1:392971033516:059fs536ub/*/GET/hello
- Review the policy:
- Name: ExecuteAPI
- User
- Modify invocation credentials
- Invoke with caller credentials:
false
- Deploy API
- Invoke with caller credentials:
- Test in Postman
- Authorization:
- AWS Signature
- Provide correct AccessKey, SecretKey and Region
- AWS Signature
- GET
https://059fs536ub.execute-api.eu-north-1.amazonaws.com/Prod/hello
- Authorization:
Generate JWT token
- use JWT.io
{
"sub": "user1",
"name": "Art Shyshkin",
"iat": 1516239022,
"data": "My custom data"
}
- jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMSIsIm5hbWUiOiJBcnQgU2h5c2hraW4iLCJpYXQiOjE1MTYyMzkwMjIsImRhdGEiOiJNeSBjdXN0b20gZGF0YSJ9.hAQ9JZGH2dxRPIL9W2th1UJMhNKZa4mZd7fLYUFQK-w
- install
jwt-decode
npm install jwt-decode --save
- Cognito console ->
- Manage User Pools -> Create a user pool
- Pool name:
riyaz-demo-pool
- Step through settings:
- Just username
- Which standard attributes do you want to require -> uncheck
email
- What password strength: 8, lowercase letters
- No MFA, no email or phone verification
- App client
- Add app client
- Name:
Riyaz Demo Client
- Generate client secret: no
- ALLOW_ADMIN_USER_PASSWORD_AUTH: false
- ALLOW_CUSTOM_AUTH: false
- ALLOW_USER_PASSWORD_AUTH: true
- ALLOW_USER_SRP_AUTH: false
- ALLOW_REFRESH_TOKEN_AUTH: true
- sign-up
aws cognito-idp sign-up --client-id <value> --username <value> --password <value>
- secret:
1234art1234
{
"UserConfirmed": false,
"UserSub": "92515850-479f-4615-9473-69aae8326a5d"
}
- admin-confirm-sign-up
aws cognito-idp admin-confirm-sign-up --user-pool-id <value> --username <value>
- ok
- admin-initiate-auth
aws cognito-idp admin-initiate-auth --user-pool-id <value> --client-id <value> --auth-flow <value>
aws cognito-idp admin-initiate-auth --user-pool-id <value> --client-id <value> --auth-flow USER_PASSWORD_AUTH --auth-parameters USERNAME=<value>,PASSWORD=<password>
- Error I did not allowed
ALLOW_ADMIN_USER_PASSWORD_AUTH
- initiate-auth
aws cognito-idp initiate-auth --client-id <value> --auth-flow USER_PASSWORD_AUTH --auth-parameters USERNAME=<value>,PASSWORD=<password>
{
"ChallengeParameters": {},
"AuthenticationResult": {
"AccessToken": "eyJra...UyzJrS6wZA",
"ExpiresIn": 3600,
"TokenType": "Bearer",
"RefreshToken": "ey...U6g",
"IdToken": "eyJra...gl9vw"
}
}
aws cognito-idp initiate-auth --generate-cli-skeleton
- copy output and paste into init-auth-skeleton.json
aws cognito-idp initiate-auth --cli-input-json file://init-auth-skeleton.json >> res.json
Step functions console:
- Create State Machine
- Write you workflow in code
{
"Comment": "A Hello World example of the Amazon States Language using Pass states",
"StartAt": "Hello",
"States": {
"Hello": {
"Type": "Pass",
"Result": "Hello",
"Next": "World"
},
"World": {
"Type": "Pass",
"Result": "World",
"End": true
}
}
}
- State machine name:
HelloWorldStateMachine
- Permissions: Create new role
- Create
- Start execution
- Name: uuid by aws (can be changed)
- Input
{
"message": "This is my first state machine"
}
- Start execution
Waiting for
- my 13:08
- UTC 11:08
- "2022-01-23T13:08:00+02:00"
- Standard
- Price: 25$ per 1M transitions
- my StateMachine has 10 transitions
- 1 M executions * 10 trans/exec = 10M transitions
- total 250$
- Express
- Price:
- 1$ per 1M executions
- 0.00001667$ per GB*s
- 1M executions:
- 1$ (requests)
- 64MB*2.75s(~took 1 execution)*1M(executions)*0.00001667$/1024 (MB in GB) = 2.865$
- total 3.87$
sls create -t aws-nodejs -p hello-serverless
sls invoke local -f hello
serverless invoke local -f hello -d '{\"key\":\"value\"}'
(PowerShell)- or
sls invoke local -f hello -d {\"key\":\"value\"}
(CMD)
- Deploy entire stack
sls deploy
sls deploy --verbose
- too long
- Deploy only function
sls deploy function -f hello
- Remove stack
sls remove
- Override parameters (i.e. stage)
sls deploy --stage prod
VPC console
- Security Groups
- Default:
sg-24aebf45
- Subnets: copy 2 of 3 subnets
- Deploy entire stack
- View Lambda Role
- Attached policy: AWSLambdaVPCAccessExecutionRole
npm init
npm install --save-dev serverless-offline
sls offline
sls logs -f addFunction -s dev
sls logs -f addFunction
(with default stage)sls logs -f addFunction --startTime 5m
(last 5 minutesdeprecated)sls logs -f addFunction --tail
Create new project sls-cicd
outside this Git repo to prevent possible conflicts with GitHub origin
git init
- add
.gitignore
git status
git checkout -b dev
- create new branch devgit status
- on branch devgit add .
- add to commit all the files from current foldergit commit -am "first commit"
git checkout -b master
- create new branch master
- Create Repository
- CodeCommit Console
- Create Repository
- Name:
sls-cicd-repo
- Description:
Serverless CI/CD Demo Repository
- Name:
- Create User
- IAM Console
- Users -> Add User
- Name:
git-service-user
- Access type:
Access key - Programmatic access
- Permissions -> Attach directly ->
AWSCodeCommitFullAccess
- Create user
- NO NEED TO SAVE ACCESS KEYS
- Close
- Name:
- HTTPS Git credentials for AWS CodeCommit
- IAM Console -> Users -> git-service-user
- Security credentials
- HTTPS Git credentials for AWS CodeCommit
- Generate credentials -> Download
- Get Repository URL
- CodeCommit Console
sls-cicd-repo
- Add origin repo
git remote add origin https://git-codecommit.eu-north-1.amazonaws.com/v1/repos/sls-cicd-repo
- Switch to dev branch
git checkout dev
- Push local branch dev to origin
git push --set-upstream origin dev
- provide credentials (I was not asked because previously had creds for art_admin user)
- Push master branch
git checkout master
git status
git push --set-upstream origin master
- Switch to dev branch
git checkout dev
- Modify code
- Commit changes
git commit -am "v2"
- Merge master with dev
git checkout master
git merge dev
- Push master branch to CodeCommit
git push
- Push dev branch to CodeCommit
git checkout dev
git push
- Change default branch to master
- CodeCommit console -> Settings -> Default branch -> master -> Save
- Create Role for CodeBuild
- IAM console -> Role -> Create
- AWS Service -> Code Build -> AdministratorAccess
- Role name: CodeBuild_Serverless_Admin
- Create CodeBuild project
- CodeBuild Console -> create project
- Project name:
sls-cicd
- Source provider: AWS CodeCommit
- Repository:
sls-cicd-repo
- Branch: master
- Environment image: Managed image
- Operating System: Amazon Linux 2
- Runtime: Standard
- Use a buildspec file: buildspec.yml
- Service Role: CodeBuild_Serverless_Admin
- Additional configuration:
- Environment variables:
- ENV_NAME: dev
- Save
- CodeBuild console
- Build project -> sls-cicd
- Start build
- CodePipeline console
- Create pipeline
- Name:
sls-cicd-pipeline
- Source provider: AWS CodeCommit
- Repository:
sls-cicd-repo
- Branch: master
- Build provider: AWS CodeBuild
- Project name:
sls-cicd
- Skip deploy stage
- Create pipeline
- Modify source code
- Commit
- Push to master
- Add manual approval
- CodePipeline console
sls-cicd-pipeline
-> Edit- after
Build
add stage- Name:
ApproveForProduction
- Name:
- Add Action group
- Action name:
MyApprove
- Action provider: Manual approval
- SNS topic ARN - optional
- Create new SNS topic
- Name:
sls-cicd-approval
- Create subscription
- Protocol: Email
- Endpoint:
- Visit Email -> Confirm subscription
- URL for review
- for example
https://53fdsmnq7i.execute-api.eu-north-1.amazonaws.com/dev/message
- for example
- Comments:
- Kindly review and approve
- Action name:
- Add production build
- Add stage:
ProdBuild
- Add Action group:
CodeBuildProd
- Action provider: CodeBuild
- Project name: create new project
sls-cicd-prod
- Operating system: Amazon Linux 2
- Runtime: Standard
- Role:
CodeBuild_Serverless_Admin
- Timeout: 5 minutes
- Environment Variables:
- ENV_NAME: prod
- Continue to CodePipeline
- Input artifact: SourceArtifact
- Add Action group:
- Save
- Change Source Code
- commit
- push
- Check email
- Approve or reject
- Review
Awesome work. Approved
sls create -t aws-nodejs -p sls-notes-backend
npm init -y
npm install --save aws-sdk moment underscore uuid
- Init Git for sls-notes-backend
git init
git checkout -b master
git checkout -b dev
git add .
git commit -am "first commit"
- Create new remote repository
- CodeCommit console ->
- Create repository:
sls-notes-backend-repo
- Copy repo's URL
- Add Remote origin into git
git remote add origin <repo's URL>
git remote -v
- verify origin
- Push dev branch to origin
git status
- check everything is okgit push --set-upstream origin dev
- Push master branch to origin
git checkout -b master
git status
- all okgit push --set-upstream origin master
- Set default branch to master
- CodeCommit console -> Settings -> Default branch -> master
- Create pipeline
- CodePipeline console
- Create pipeline:
sls-notes-backend-pipeline
- Branch:
master
- Build provider:
CodeBuild
- Create project:
sls-notes-backend-codebuild
- Existing role: CodeBuild_Serverless_Admin
- Environment variable:
- ENV_NAME:
prod
- ENV_NAME:
- Continue to CodePipeline
- Create project:
- Skip deployment stage
- Create pipeline
- Create buildspec.yml
- Commit, push
sls offline
npm install --save-dev serverless-domain-manager
- Request certificate
- ACM Console
- Switch to US-EAST-1
- Request certificate -> Request a public certificate
- Fully qualified domain name:
shyshkin.net
- Add another name to this certificate:
*.shyshkin.net
- Select validation method: DNS
- Request
- Validate ownership
- Certificates -> pending validation
- Create Records in Route53
- Wait for a few minutes
- Add name to the certificate
- Certificates -> Tags -> Manage
- Name: shyshkin.net
- Check propagation is completed
- dnschecker.org
- shyshkin.net
- NS
- API Gateway console
- Custom domain names -> NO
- Create domain
sls create_domain
- Verify custom domain name was created
- API Gateway console
- Custom domain names -> notesapi.shyshkin.net
- API Mappings:
- No API mappings have been configured for this domain
- need to redeploy API
- Redeploy API
- git commit
- git push
- Wait for pipeline to complete
- Verify API Mappings
- Verify
notesapi.shyshkin.net
in Route 53
- Test through http client
npm run build:watch
- 'npm start' - will start local-server.js (NextJS)
- sls-notes-backend>
sls offline
- start rest api locally - go http://localhost:4000
- Manually create S3 Bucket
- S3 console
- Create bucket:
notesapp.shyshkin.net
- Region:
eu-north-1
- Block all public access: false
- Create bucket
- Modify Bucket policy
- Permissions -> Bucket policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow all users to read web app content",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::notesapp.shyshkin.net/*"
}
]
}
- Add content to S3 bucket
aws s3 sync ./public/ s3://notesapp.shyshkin.net
- Create repository
- CodeCommit console
- create repo
sls-notes-webapp-repo
- Build app for prod
npm run build:prod
- Init git
git init
git add .
git commit -am "init webapp"
git remote add origin https://git-codecommit.eu-north-1.amazonaws.com/v1/repos/sls-notes-webapp-repo
git push --set-upstream origin master
git checkout -b dev
git push --set-upstream origin dev
- Create pipeline in CodePipeline
sls-notes-webapp-pipeline
- Enable static website hosting
- S3 console
- Properties
- Static Website Hosting
- Edit
- Enable
- Host a static website
- Index document - index.html
- Error document - index.html
- Visit website
http://notesapp.shyshkin.net.s3-website.eu-north-1.amazonaws.com
- Create bucket for logs
art-sls-logs
- Enable Server access logging for bucket
notesapp.shyshkin.net
- Properties
- Server access logging
- Enable
- Target bucket:
s3://art-sls-logs/logs/notesapp.shyshkin.net/access/
- Route 53 console
- Create record
notesapp
- Alias
- Alias to S3 website endpoint
- Region: eu-north-1
- s3-website.eu-north-1.amazonaws.com
- Create record
- Test it
http://notesapp.shyshkin.net
- CloudFront console
- Create distribution
- Origin domain:
notesapp.shyshkin.net.s3.eu-north-1.amazonaws.com
- Viewer protocol policy:
Redirect HTTP to HTTPS
- Compress objects automatically:
yes
- Alternate domain name (CNAME):
notesapp.shyshkin.net
- Custom SSL certificate:
shyshkin.net
- Default root object: index.html
- Standard logging: Off (for now)
- Create distribution
- Enable access control list ACL of logs bucket
- S3 console ->
art-sls-logs
- Permissions -> Object Ownership -> Edit
- ACLs enabled
- Object Ownership: Bucket owner preferred
- Enable CloudFront Standard logging
- Distribution -> General -> Settings -> Edit
- Standard logging -> On
- S3 Bucket:
art-sls-logs.s3.amazonaws.com
- Prefix:
logs/notesapp.shyshkin.net/cdn/
- Save changes
- Route 53
- notesapp.shyshkin.net -> Edit Record
- Alias to CloudFront distribution
d12kfvjrz2b8er.cloudfront.net
Copy distribution ID from ARN
arn:aws:cloudfront::392971033516:distribution/E2XH5SB8MO9S0Y
E2XH5SB8MO9S0Y
- Update buildspec.yml file
- google for
google api console
https://console.developers.google.com/apis/dashboard
- Select a project -> New project
- Name:
Serverless Notes App
- Create
- Name:
- Select project
- OAuth consent screen
- External -> create
- App name:
Serverless Notes App
- Authorized Domains:
shyshkin.net
- Add test user:
[email protected]
- Credentials
- Create credentials -> OAuth Client ID
- Application type: Web application
- Name:
Serverless Notes Web App
- Authorized JavaScript origins
- Create
- Copy Client ID
- Cognito Console
- Manage Identity Pools
- Create new Identity Pool
- Name:
Serverless Notes App
- Authentication providers:
- Google+: paste
- Create pool
- Name:
- Identify the IAM roles to use with your new identity pool
- Allow
- Getting started with Amazon Cognito
- Platform: JavaScript
- View code snippet
- Edit identity pool
- Authenticated role -> view name
- IAM console
- Roles: Cognito_ServerlessNotesAppAuth_Role
- Add permissions -> create inline policy
- Service:
ExecuteAPI
- Actions:
Invoke
- Resources:
*
(All)
- Service:
- Review Policy
- Name:
NotesAppExecuteApiAccess
- Name:
- copy new src files
npm install
npm run build:watch
- modify index.html
npm install --save aws4 @types/aws4
npm run build:prod
- 'npm start' - will start local-server.js (NextJS)
- go http://localhost:4000
- got an error
- Cannot read properties of undefined (reading 'length')
- Enable CloudWatch Logs for API
- API Gateway console
- Stages -> prod -> Logs/Tracing
- Enable CloudWatch Logs
- Log Level: INFO
- Log full requests/responses data
- Save changes