Use Lambda@Edge for Angular Deployment

If your Angular application requires dynamic functionality (e.g., authentication, API calls, etc.) that can't be handled by static assets alone, you can set up Lambda@Edge functions to process requests.

  • Step 1: Create a Lambda@Edge function that is triggered on specific CloudFront events, such as:
    • Viewer Request: Modify the request before it reaches CloudFront.
    • Origin Request: Modify the request before it reaches your origin (e.g., S3).
    • Origin Response: Modify the response from your origin (e.g., add headers, perform authentication).
    • Viewer Response: Modify the response before it is sent to the viewer.
  • Step 2: Write your Lambda@Edge function in Node.js or Python to handle logic like:
    • Redirecting users based on authentication.
    • Serving custom content for certain requests.
    • Modifying HTTP headers for security (e.g., HSTS, CORS).
  • Step 3: Deploy your Lambda function to an AWS region (e.g., us-east-1) and attach it to CloudFront distribution events (like viewer request or origin request).

To implement Lambda@Edge step by step, here’s a detailed guide on how to configure it with an Amazon CloudFront distribution to enhance or process requests for your Angular (or any static web) application:

Step 1: Create and Deploy Your Angular Application

  1. Build the Angular application:

    • Run the following command in your Angular project directory to create a production build:
      ng build --prod
      
    • This will generate static files (HTML, CSS, JavaScript) in the dist/ directory.
  2. Upload to S3:

    • Create an Amazon S3 bucket to host your static assets.
    • Upload the contents of the dist/ directory to your S3 bucket.
      • Go to the AWS S3 console, select your bucket, and use the Upload button to upload files.
    • Set the bucket permissions to allow public read access for the content, or you can restrict access via CloudFront later.

Step 2: Create a CloudFront Distribution

  1. Navigate to CloudFront:

    • In the AWS Management Console, go to CloudFront and click Create Distribution.
  2. Configure the Distribution:

    • For the Origin Domain Name, select your S3 bucket where the Angular app is hosted.
    • Set Viewer Protocol Policy to "Redirect HTTP to HTTPS" or "HTTPS only" to ensure secure connections.
    • Leave other default settings unless you need specific configurations like caching or security headers.
  3. Enable Lambda@Edge:

    • In the Behaviors tab, select the default behavior or create a new one for your Angular app’s path (/*).
    • Scroll down to the Lambda Function Associations section.
    • Choose which CloudFront event you want to trigger the Lambda function (Viewer Request, Viewer Response, Origin Request, Origin Response).

Step 3: Create the Lambda@Edge Function

  1. Navigate to Lambda Console:

    • Go to the AWS Management Console and select Lambda.
  2. Create a Lambda Function:

    • Click Create Function and select Author from Scratch.
    • Choose Node.js as the runtime, since Lambda@Edge primarily supports Node.js and Python.
    • Give the function a name, like edgeFunctionForAngularApp.
    • Under Permissions, you can use the default role. Ensure that the Lambda function has the required permissions to access S3 or any other services, if necessary.
  3. Write Lambda Code:

    • Write a simple Lambda function based on the event you selected in CloudFront (for example, Viewer Request to modify the request before it reaches CloudFront). Here’s a basic example:

      exports.handler = async (event) => {
        const request = event.Records[0].cf.request
        const headers = request.headers
      
        // Example: Add security headers
        headers['strict-transport-security'] = [
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=31536000; includeSubDomains; preload',
          },
        ]
        headers['x-content-type-options'] = [
          { key: 'X-Content-Type-Options', value: 'nosniff' },
        ]
      
        return request
      }
      
  4. Deploy Lambda@Edge to CloudFront:

    • After writing your code, click Deploy. Then, choose Deploy to Lambda@Edge in the Lambda Console.
    • Select the CloudFront distribution and region (usually us-east-1 for Lambda@Edge) where you want to deploy the function.
    • Choose the event (e.g., Viewer Request) for which the function should be triggered.
    • Deploy the function.

Step 4: Test the CloudFront and Lambda@Edge Setup

  1. Access the CloudFront URL:

    • After your CloudFront distribution has propagated (it might take some time), test your Angular application by accessing the CloudFront distribution URL (e.g., https://xyz123.cloudfront.net).
    • Verify that the Angular app is served correctly and that any Lambda@Edge logic is functioning (e.g., headers added, redirects happening, or other request/response modifications).
  2. Monitor Logs and Metrics:

    • Check the CloudWatch Logs for Lambda to debug any issues or monitor the invocations of the Lambda function.
    • In the CloudFront console, you can also monitor the requests and responses, and ensure the behavior is as expected.

Step 5: Modify Lambda@Edge for Specific Use Cases

You can now enhance or modify the Lambda@Edge function based on your needs:

  • Authentication: Check headers or cookies and redirect unauthenticated users to a login page.
  • Dynamic Content: Modify requests based on user location or user-agent.
  • Error Pages: Use Lambda@Edge to serve custom error pages if the Angular app encounters issues.
  • Security Headers: Add headers like Content-Security-Policy, X-Frame-Options, etc.

Step 6: Update and Version Control Your Lambda@Edge

  1. Every time you update the Lambda function, create a new version.
  2. Deploy the new version to CloudFront from the Lambda console.
  3. CloudFront automatically updates the Lambda@Edge function globally. Keep in mind it may take some time for the changes to propagate across all edge locations.

Example: Lambda@Edge Use Case (Viewer Request)

Here’s an example where Lambda@Edge modifies headers during a Viewer Request:

exports.handler = async (event) => {
  const request = event.Records[0].cf.request
  const headers = request.headers

  // Example: Redirect users from http to https
  if (request.headers['cloudfront-forwarded-proto'][0].value === 'http') {
    return {
      status: '301',
      statusDescription: 'Moved Permanently',
      headers: {
        location: [
          {
            key: 'Location',
            value: 'https://' + request.headers.host[0].value + request.uri,
          },
        ],
      },
    }
  }

  // Example: Add Security Headers
  headers['strict-transport-security'] = [
    {
      key: 'Strict-Transport-Security',
      value: 'max-age=31536000; includeSubDomains',
    },
  ]
  headers['x-content-type-options'] = [
    { key: 'X-Content-Type-Options', value: 'nosniff' },
  ]

  return request
}

Summary:

  1. Host Angular App on S3: Build and store your app as static assets in an S3 bucket.
  2. Distribute via CloudFront: Create a CloudFront distribution to serve your Angular app globally.
  3. Create Lambda@Edge: Write Lambda functions to modify or enhance requests or responses at the edge.
  4. Deploy and Monitor: Deploy your Lambda@Edge functions and monitor them via CloudWatch and CloudFront logs.

This setup allows you to serve your Angular app efficiently, with the ability to handle dynamic logic, security enhancements, and request manipulation at the edge.