Explore full-stack cloud-native web application development with Green Boost - AWS Prescriptive Guidance

Explore full-stack cloud-native web application development with Green Boost

Created by Ben Stickley (AWS) and Amiin Samatar (AWS)

Environment: PoC or pilot

Technologies: Web & mobile apps

Workload: Open-source

AWS services: Amazon Aurora; AWS CDK; Amazon CloudFront; AWS Lambda; AWS WAF

Summary

In response to the evolving needs of developers, Amazon Web Services (AWS) recognizes the critical demand for an efficient approach to developing cloud-native web applications. The AWS focus is on helping you to overcome common roadblocks associated with deploying web apps on the AWS Cloud. By harnessing the capabilities of modern technologies such as TypeScript, AWS Cloud Development Kit (AWS CDK), React, and Node.js, this pattern aims to streamline and expedite the development process.

Underpinned by the Green Boost (GB) toolkit, the pattern offers a practical guide to constructing web applications that fully use the extensive capabilities of AWS. It acts as a comprehensive roadmap, leading you through the process of deploying a fundamental CRUD (Create, Read, Update, Delete) web application integrated with Amazon Aurora PostgreSQL-Compatible Edition. This is accomplished by using the Green Boost command line interface (Green Boost CLI) and establishing a local development environment.

Following the successful deployment of the application, the pattern delves into key components of the web app, including infrastructure design, backend and frontend development, and essential tools such as cdk-dia for visualization, facilitating efficient project management.

Prerequisites and limitations

Prerequisites

Product versions

  • AWS SDK for JavaScript version 3

  • AWS CDK version 2

  • AWS CLI version 2.2

  • Node.js version 18

  • React version 18

Architecture

Target technology stack

  • Amazon Aurora PostgreSQL-Compatible Edition

  • Amazon CloudFront

  • Amazon CloudWatch

  • Amazon Elastic Compute Cloud (Amazon EC2)

  • AWS Lambda

  • AWS Secrets Manager

  • Amazon Simple Notification Service (Amazon SNS)

  • Amazon Simple Storage Service (Amazon S3)

  • AWS WAF

Target Architecture

The following diagram shows that user requests pass through Amazon CloudFront, AWS WAF, and AWS Lambda before interacting with an S3 bucket, an Aurora database, an EC2 instance, and ultimately reaching developers. Administrators, on the other hand, use Amazon SNS and Amazon CloudWatch for notifications and monitoring purposes.

Process to deploy a CRUD web app integrated with Amazon Aurora PostgreSQL by using Green Boost CLI.

To gain a more in-depth look at the application after deployment, you can create diagram by using cdk-dia, as shown in the following example.

These diagrams showcase the web application architecture from two distinct angles. The cdk-dia diagram offers a detailed technical view of the AWS CDK infrastructure, highlighting specific AWS services such as Amazon Aurora PostgreSQL-Compatible and AWS Lambda. In contrast, the other diagram takes a broader perspective, emphasizing the logical flow of data and user interactions. The key distinction lies in the level of detail: The cdk-dia delves into technical intricacies, while the first diagram provides a more user-centric view.

First diagram shows user-centric view; cdk-dia diagram shows technical infrastructure view.

Creation of the cdk-dia diagram is covered in the epic Understand the app infrastructure by using AWS CDK.

Tools

AWS services

  • Amazon Aurora PostgreSQL-Compatible Edition is a fully managed, ACID-compliant relational database engine that helps you set up, operate, and scale PostgreSQL deployments.

  • AWS Cloud Development Kit (AWS CDK) is a software development framework that helps you define and provision AWS Cloud infrastructure in code.

  • AWS Command Line Interface (AWS CLI) is an open-source tool that helps you interact with AWS services through commands in your command-line shell.

  • Amazon CloudFront speeds up distribution of your web content by delivering it through a worldwide network of data centers, which lowers latency and improves performance.

  • Amazon CloudWatch helps you monitor the metrics of your AWS resources and the applications you run on AWS in real time.

  • Amazon Elastic Compute Cloud (Amazon EC2) provides scalable computing capacity in the AWS Cloud. You can launch as many virtual servers as you need and quickly scale them up or down.

  • AWS Lambda is a compute service that helps you run code without needing to provision or manage servers. It runs your code only when needed and scales automatically, so you pay only for the compute time that you use.

  • AWS Secrets Manager helps you replace hardcoded credentials in your code, including passwords, with an API call to Secrets Manager to retrieve the secret programmatically.

  • AWS Systems Manager helps you manage your applications and infrastructure running in the AWS Cloud. It simplifies application and resource management, shortens the time to detect and resolve operational problems, and helps you manage your AWS resources securely at scale. This pattern uses AWS Systems Manager Session Manager.

  • Amazon Simple Storage Service (Amazon S3) is a cloud-based object storage service that helps you store, protect, and retrieve any amount of data.Amazon Simple Notification Service (Amazon SNS) helps you coordinate and manage the exchange of messages between publishers and clients, including web servers and email addresses.

  • AWS WAF is a web application firewall that helps you monitor HTTP and HTTPS requests that are forwarded to your protected web application resources

Other tools

  • Git is an open-source, distributed version control system.

  • Green Boost is a toolkit for building web apps on AWS.

  • Next.js is a React framework for adding features and optimizations.

  • Node.js is an event-driven JavaScript runtime environment designed for building scalable network applications.

  • pgAdmin is an open-source management tool for PostgreSQL. It provides a graphical interface that helps you create, maintain, and use database objects.

  • pnpm is a package manager for Node.js project dependencies.

Best practices

See the Epics section for more information about the following recommendations:

  • Monitor infrastructure by using Amazon CloudWatch Dashboards and alarms.

  • Enforce AWS best practices by using cdk-nag to run static infrastructure as code (IaC) analysis.

  • Establish DB port forwarding through SSH (Secure Shell) tunneling with Systems Manager Session Manager, which is more secure than having a publicly exposed IP address.

  • Manage vulnerabilities by running pnpm audit.

  • Enforce best practices by using ESLint to perform static TypeScript code analysis, and Prettier to standardize code formatting.

Epics

TaskDescriptionSkills required

Install the Green Boost CLI.

To install Green Boost CLI, run the following command.

pnpm add -g gboost
App developer

Create a GB app.

  1. To create an app by using Green Boost, run the command gboost create.

  2. Choose the CRUD App with Aurora PostgreSQL template.

App developer

Install dependencies and deploy the app.

  1. Navigate to the project directory: cd <your directory>.

  2. To install dependencies, run the command pnpm i.

  3. Navigate to the infra directory: cd infra.

  4. To deploy the app locally, run the command pnpm deploy:local.

    This is an alias for a cdk deploy ... command defined in infra/package.json.

Wait for deployment to finish (approximately 20 minutes). While you’re waiting, monitor AWS CloudFormation stacks in the CloudFormation console. Notice how the constructs defined in the code map to the resource deployed. Review the CDK Construct tree view in the CloudFormation console.

App developer

Access the app.

After deploying your GB app locally, you can access it using the CloudFront URL. The URL is printed in the terminal output, but it can be a bit overwhelming to find. To find it more quickly, use the following steps:

  1. Open the terminal where you ran the pnpm deploy:local command.

  2. Look for a section in the terminal output that resembles the following text.

    myapp5stickbui9C39A55A.CloudFrontDomainName = d1q16n5pof924c.cloudfront.net

    The URL will be unique to your deployment.

Alternatively, you can find the CloudFront URL by accessing the Amazon CloudFront console:

  1. Sign in to the AWS Management Console and navigate to the CloudFront service.

  2. Look for the latest deployed distribution in the list.

Copy the Domain Name that is associated with the distribution. It will look similar to your-unique-id.cloudfront.net.

App developer
TaskDescriptionSkills required

View the CloudWatch Dashboard.

  1. Open the CloudWatch console and choose Dashboards.

  2. Select the dashboard that has the name <appId>-<stageName>-dashboard.

  3. Review the dashboard. What resources are being monitored? What metrics are being recorded? This dashboard is made possible by the open-source construct cdk-monitoring-constructs.

App developer

Enable alerts.

A CloudWatch Dashboard helps you to actively monitor your web app. To passively monitor your web app, you can enable alerting.

  1. Navigate to /infra/src/app/stateless/monitor-stack.ts, which defines the monitor stack.

  2. Uncomment the following line, and replace admin@example.com with your email address.

    onAlarmTopic.addSubscription(new EmailSubscription("admin@example.com"));
  3. Add the following import information to the top of the file.

    import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
  4. Within infra/, run the following command.

    cdk deploy "*/monitor" --exclusively.
  5. To confirm your subscription to the SNS topic that is intitated when a monitoring alarm is initiated, choose the link in the email message.

App developer
TaskDescriptionSkills required

Create an architecture diagram.

Generate an architecture diagram of your web app by using cdk-dia. Visualizing the architecture helps improve understanding and communication among team members. It provides a clear overview of the system's components and their relationships.

  1. Install Graphviz.

  2. Within infra/, run the command pnpm cdk-dia.

  3. View your infra/diagram.png.

App developer

Use cdk-nag to enforce best practices.

Use cdk-nag to help you maintain secure and compliant infrastructure by enforcing best practices, reducing the risk of security vulnerabilities and misconfigurations.

  1. Explore cdk-nag's best practice enforcement through its rules section, including checks from the AWS Solutions Library's Rules Pack.

  2. To see how cdk-nag enforces rules, make a change in the code. For example, in infra/src/app/stateful/data-stacks.ts, change storageEncrypted: true to storageEncrypted: false.

  3. Within infra/, run the command cdk synth "*/data". During synthesis, you will encounter a build error that indicates a rule violation.

    AwsSolutions-RDS2: The RDS instance or Aurora DB cluster does not have storage encryption enabled.

    This error showcases how cdk-nag is a security mechanism for enforcing infrastructure best practices and preventing security misconfigurations.

  4. If needed, you can also suppress rules at different scopes. For example, to suppress AwsSolutions-RDS2, add the following code below the instantiation of DbIamCluster.

    NagSuppressions.addResourceSuppressions( cluster.node.findChild("Resource"), [ { id: "AwsSolutions-RDS2", reason: "Customer requirement necessitates having unencrypted DB storage", }, ], );
  5. After suppression, run cdk synth "*/data" again. Your AWS CDK app should now synthesize successfully. You can find all suppressed rules in infra/cdk.out/assembly-<appId>-<stageName>/AwsSolutions-<appId>-<stageName>-${stackId}-NagReport.csv.

App developer
TaskDescriptionSkills required

Acquire environment variables.

To obtain the required environment variables, use the following steps:

  1. To find the DB_BASTION_ID, sign in to the console, and navigate to the EC2 console. Choose Instances (running), and find the row that contains <stageName>-ssm-db-bastion Name. The instance ID starts with i-.

  2. To find the DB_ENDPOINT, on the Amazon Relational Database Service (Amazon RDS) console, choose DB Instances, and select the regional cluster that has a DB identifier starting with <appId>-<stageName>-data-. Locate the writer instance endpoint, which ends with rds.amazonaws.com.

App developer

Establish port forwarding.

To establish port forwarding, use the following steps:

  1. Install the AWS Systems Manager Session Manager plugin.

  2. Start port forwarding by running pnpm db:connect within core/ to establish a secure connection through the bastion host.

  3. After you see the text Waiting for connections..., in your terminal, an SSH tunnel has been successfully established between your local machine and the Aurora server through the EC2 bastion host.

App developer

Adjust the Systems Manager Session Manager timeout.

(Optional) If the default 20-minute session timeout is too short, you can increase it up to 60 minutes in the Systems Manager console by choosing Session Manager, Preferences, Edit, Idle session timeout.

App developer

Visualize the database.

pgAdmin is a user-friendly open-source tool for managing PostgreSQL databases. It simplifies database tasks, allowing you to efficiently create, manage, and optimize databases. This section guides you through installing pgAdmin and using its features for PostgreSQL database management.

  1. In the Object Explorer, open the context (right-click) menu for Servers, and then choose Register, Server.

  2. On the General tab, enter <appId>-<stageName> for the Name field.

  3. To fetch the DB password, open the AWS Secrets Manager console, select the secret that has the description Generated by the CDK for the stack: <appId>-<stageName>-data, and choose the Secret Value card. Choose Retrieve Secret Value, and copy the Secret value with a key of password.

  4. On the Connection tab, enter 0.0.0 for the Host name/address field, and enter <appId>_admin for the Username field. For the Password field, use the secret that you fetched previously. Choose yes for the Save password? field.

  5. Choose Save.

  6. To view the tables, navigate to <appId>-<stageName>, Databases, <appId>_db, Schemas, <appId>, Tables.

  7. Open the context (right-click) menu for the item table, and then select View/Edit Data, All Rows.

  8. Explore the table.

App developer
TaskDescriptionSkills required

Debug the create item use case.

To debug the create item use case, follow these steps:

  1. Open the core/src/modules/item/create-item.use-case.ts file, and insert the following code.

    import { fileURLToPath } from "node:url"; // existing create-item.use-case.ts code here if (process.argv[1] === fileURLToPath(import.meta.url)) { createItemUseCase({ description: "Item 1's Description", name: "Item 1", }); }
  2. The code added in the previous step ensures the createItemUseCase function will be called when this module is run directly. Set breakpoints on the lines within this code block where you want to initiate line-by-line debugging.

  1. Open the VS Code JavaScript Debug Terminal, and then run pnpm tsx core/src/modules/item/create-item.use-case.ts to run the code with line-by-line debugging. Alternatively, you can use console.log statements, but print statements can be inadequate when you’re working with complex business logic. Line-by-line debugging gives you more context.

App developer
TaskDescriptionSkills required

Set up the development server.

  1. Navigate to ui/, and run pnpm dev to start the Next.js development server.

  2. Access your web app locally at http://localhost:3000. The Next.js development server is set up with Fast Refresh instantaneous feedback on edits made to your React components.

  3. Experiment with customizing the app bar color. Open the ui/src/components/theme/theme.tsx file and locate the section that defines the theme for the app bar. In the colorSchemes.light.palette.primary section, update the main value from colors.lagoon to colors.carrot. After making this change, save the file and observe the update in your browser.

  4. Experiment by modifying text, components, and adding new pages.

App developer
TaskDescriptionSkills required

Set up monorepo and the pnpm package manager.

  1. Review pnpm-workspace.yaml in the root of your GB repository, and notice how workspaces are defined. For more information about workspaces, see the pnpm documentation.

  2. Review ui/package.json, and notice how it references the workspace in core/ with the package name "<appId>/core": "workspace:^",.

  3. Observe how TypeScript and ESLint configuration is centralized in utility packages defined within packages/. This configuration is then used by application packages such as core/, infra/, and ui/. This is helpful when your app scales and you define more application packages, which can reference the utility packages without duplicating configuration code.

App developer

Run pnpm scripts.

Run the following commands in the root of your repository:

  1. Run pnpm lint. This command runs static code analysis with ESLint.

  2. Run pnpm typecheck. This command runs the TypeScript compiler to check the types of your code.

  3. Run pnpm test. This command runs Vitest to run unit tests.

Notice how these commands are run in all workspaces. The commands are defined in each workspace's package.json#scripts field.

App developer

Use ESLint for static code analysis.

To test the static code analysis capability of ESLint, do the following:

  1. First, ensure the VS Code ESLint extension (ID: dbaeumer.vscode-eslint) is installed. We recommend also installing VS Code Error Lens (ID: usernamehw.errorlens) to see errors inline.

  2. In your code, purposefully include a line of code that uses the eval() function, as shown in the following example.

    const userInput = "import("fs").then((fs) => console.log(fs.readFileSync("/etc/passwd", { encoding: "utf8" })))"; eval(userInput);

    Important: This is for testing purposes only. Using eval() is considered potentially dangerous and should be avoided because of security risks.

  3. After you include the eval() line, open your code editor to confirm that ESLint indicated the code smell by using red squiggles.

  4. Review ESLint plugins and configuration at packages/eslint-config-{node,next}/.eslintrc.cjs.

App developer

Manage dependencies and vulnerabilities.

  1. To identify any Common Vulnerabilities and Exposures (CVEs), run pnpm audit in the root of your repository.

    You should see No known vulnerabilities found.

  2. Install an intentionally vulnerable package within core/ by running pnpm add minimist@0.2.3, and then run pnpm audit. Notice the vulnerability being reported.

  3. Uninstall the vulnerable package within core/ by running pnpm remove minimist.

App developer

Pre-commit hooks with Husky.

  1. Make a couple small changes in TypeScript files throughout the repository. The changes can be as basic as adding comments.

  2. Stage and commit these changes by using git add -A and then git commit -m "test husky".

    The Husky pre-commit hook trigger, which is defined in .husky/pre-commit, runs the command pnpm lint-staged.

  3. Observe how lint-staged runs commands specified in */.lintstagedrc.js files throughout the repository on files that have been staged by Git.

These tools are mechanisms to help prevent bad code from making its way into your application.

App developer
TaskDescriptionSkills required

Remove the deployment from your account.

  1. To tear down the infrastructure that you provisioned in the first epic, by run pnpm destroy:local in infra/.

  2. Wait 15 minutes after pnpm destroy:local is complete, and then delete the retained Lambda@Edge function by searching for your app ID in the Lambda console. Lambda@Edge functions are replicated., which makes them difficult to delete. For more information about deleting Lambda@Edge functions, see the CloudFront documentation.

App developer

Troubleshooting

IssueSolution

Unable to establish port forwarding

Ensure that your AWS credentials are properly configured and have the necessary permissions.

Double-check that the bastion host ID (DB_BASTION_ID) and database endpoint (DB_ENDPOINT) environment variables are correctly set.

If you still encounter issues, see the AWS documentation for troubleshooting SSH connections and Session Manager.

Website isn't loading on localhost:3000

Confirm that the terminal output indicates successful port forwarding, including the forwarding address.

Ensure there are no conflicting processes using port 3000 on your local machine.

Verify that the Green Boost application is properly configured and running on the expected port (3000).

Check your web browser for any security extensions or settings that might block local connections.

Error messages during local deployment (pnpm deploy:local)

Review the error messages carefully to identify the cause of the issue.

Verify that the necessary environment variables and configuration files are correctly set.

Related resources