The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions
Asked Answered
U

3

7

So as a pretext, I've got less than no idea what to do about this. I've researched for about two hours and normally I would just keep going but none of the information I've found has been useful. I suspect this would have something to do with the YAML (serverless.yml) file but I am unsure. I've made several updates to the file so I will post the initial code and the current code though no difference has been made. The code worked flawlessly in development but throws errors in production. You can see https://www.evote.space to replicate this.

Current

myNextApplication:
  service: myService
  component: "@sls-next/[email protected]"
  provider:
    name: aws
    runtime: nodejs12.x
    stage: dev
    profile: evote
    iam:
    role: rolenamegoesherebutnotonstackoverflow
  inputs:
    domain: "evote.space"
  functions:
    createuser:
      handler: data.createuser
    readTable:
      handler: data.readTable
  resources:
    Resources:
      usersTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: Users
          AttributeDefinitions:
          - AttributeName: userHash
            AttributeType: N
          KeySchema:
          - AttributeName: userHash
            KeyType: HASH
      votersTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: Voters
          AttributeDefinitions:
          - AttributeName: voterHash
            AttributeType: N
          KeySchema:
          - AttributeName: voterHash
            KeyType: HASH
      electionsTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: Elections
          AttributeDefinitions:
          - AttributeName: electionHash
            AttributeType: N
          KeySchema:
          - AttributeName: electionHash
            KeyType: HASH
      ballotsTable:
        Type: AWS::DynamoDB::Table
        Properties:
          TableName: Ballots
          AttributeDefinitions:
          - AttributeName: ballotHash
            AttributeType: N
          KeySchema:
          - AttributeName: ballotHash
            KeyType: HASH

Initial (At first deployment with error)

myNextApplication:
  service: myService
  component: "@sls-next/[email protected]"
  provider:
    name: aws
    runtime: nodejs12.x
    stage: dev
    profile: evote
  inputs:
    domain: "evote.space"

My code base is massive and made up of many pages and components. So far all that I've made is a login function but on the sign up page where it calls the api to return users (for duplicate email validation), it returns the error we're all too familiar with "Unexpected token < in JSON at position 0" if you go back then load the page again you can get the console to reveal a source on that error which reads:

503 ERROR The request could not be satisfied. The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner. If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation. Generated by cloudfront (CloudFront) Request ID: No0_qVJ3gcOpg48rMXqvgyipx4wKWmV-hRewQblZ-loyaaiVJLqGIA==

So yeah, if you can help, please do.

Edit: The code that's causing the issue is the following block

NewUser.getInitialProps = async ({ req }) => {
  if (req) {
    // this is server side
    return {
      users: await data.readTable("Users")
    };
  } else {
    // we are client side
    const response = await fetch("/api/users");
    return { users: await response.json() };
  }
};

And the api that handled this originally looked like this:

import data from "../../../data"

export default async (req, res) => {
  console.log("/api/users HIT!");
  res.status(200).json(await data.readTable("Users"));
};

But I changed it so that it can be marked as a lambda so now it looks like this (though it made no difference):

import data from "../../../data";

module.exports.read = async (event, context, callback) => {
  console.log("/api/users HIT!");
  callback(null, {statusCode: 200}).json(await data.readTable("Users"));
}
Undamped answered 14/3, 2021 at 6:39 Comment(0)
U
7

So after careful research I did the following and this is apparently a pretty common issue so I recommend anyone else suffering from this issue do exactly the following. Please remember this is with the serverless-nextjs component not just the serverless framework although the same may apply there:

  1. I carefully dug through the repository README and followed all instructions.
  2. I logged into the AWS Console and found what I thought was the primary issue but was actually a tertiary problem; The Lambda@Edge was only configured with basic CloudWatch Logging permissions. I updated it with all of the necessary privileges while ensuring best practices
  3. After updating your Lambda make sure you deploy it to Lambda@Edge (Under Actions Menu)
  4. Then I navigated to CloudWatch and checked the logs in the correct region and found errors after calling into the API.
  5. Somehow my DynamoDB tables got deleted or weren't properly replicated so I redeployed them from my SDK with npm run infra and after.

This experience is always a good one to have. Your by no means invincible to really stupid errors in your code. And 99% of the time if you're stuck and thinking it's complex and that it's unrealistic that you'll fix it, step back and ask, "What's the dumbest thing it could be?"

And it's always that.

Undamped answered 19/3, 2021 at 8:46 Comment(2)
Hi, can you expand on "I updated it with all of the necessary privileges while ensuring best practices"...any suggestions for what privileges you added?Kokoschka
@EugeneAnanin Sure, and sorry this is so late but hopefully it helps someone else, I updated it with privilege's that reflect best practice simply means I created policies that ensured I had access to edit and update the table but only that table. Best practice policies give access without overreach.Undamped
D
1

For me, using the Alpha version of Serverless, solved this error message 'The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions'

serverless.yml file:

# component: "@sls-next/[email protected]"
component: "@sls-next/[email protected]"

We can find the latest version here: https://www.npmjs.com/package/@sls-next/serverless-component

Decretory answered 1/10, 2021 at 15:13 Comment(0)
D
0

I had this issue because there was a bug in my Lambda code and it was failing.

I checked the CloudWatch logs for the Lambda function (for the region in which I was accessing the CloudFront site from, which wasn't us-east-1) and that contained error messages which made me realise the Lambda function was failing with an error.

Once I fixed the error and got the Lambda@Edge function running properly, the CloudFront error went away.

I decided to create a short test file that I could run locally on my machine with Node, that would test the Lambda@Edge function to make sure it worked without any errors before I deployed it:

// Run with `node test.mjs`

import test from 'node:test';
import assert from 'node:assert/strict';

import { handler } from './my-lambda-edge-function.mjs';

// Test a URL that returns a HTTP 302 redirect.
async function testRedirect(from, to) {
    const result = await handler({
        Records: [
            {
                cf: {
                    request: {
                        uri: from,
                    },
                },
            },
        ],
    });

    assert(result.status === '302');
    assert(result.headers.location[0].value === to);
}

// Test a URL that returns data from a different upstream file.
async function testMutate(from, to) {
    const result = await handler({
        Records: [
            {
                cf: {
                    request: {
                        uri: from,
                    },
                },
            },
        ],
    });

    assert(result.uri === to);
}

test('Mutations', async () => {
    // Make sure the Lambda@Edge adds 'index.html' onto the end of folders.
    await testMutate('/admin/', '/admin/index.html');

    // Make sure the Lambda@Edge adds '/admin' onto the front of certain URLs.
    await testMutate('/static/images/test.jpg', '/admin/static/images/test.jpg');

    // Make sure '/admin' URLs are left unchanged.
    await testMutate('/admin/templates/default.html', '/admin/templates/default.html');

    // Combination of the above.
    await testMutate('/subscribe/', '/admin/static/subscribe/index.html');
});

test('Redirects', async () => {
    // Make sure requests to the root get HTTP 302 redirected to another URL.
    await testRedirect('/', '/subscribe/');
});
Driest answered 2/9 at 2:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.