amplify-hosting icon indicating copy to clipboard operation
amplify-hosting copied to clipboard

IAM permission with NextJS

Open philschmid opened this issue 2 years ago • 56 comments

Before opening, please confirm:

App Id

AWS Region

us-east-1

Amplify Hosting feature

SSR

Question

Hello,

I have a question regarding IAM permissions. I successfully deployed NextJS 13 using amplify. Now, I want to use AWS service via the aws javascript SDK in my api/ functions. How can i provide credentials in a secure way to it? I know that i could create a user and pass the accessKeyId and secretAccessKey as env, but i would like to avoid this. How can I assign a role to my NextJs app?

philschmid avatar Dec 15 '22 21:12 philschmid

cc @hloriana

philschmid avatar Dec 15 '22 21:12 philschmid

You can change the role for your app in the settings:

image

Keep in mind that we need so basic policy permissions to deliver logs to CloudWatch, you can see them here:

image

calavera avatar Dec 15 '22 21:12 calavera

@calavera the service role is the one used in the edge lambda functions? Do i need to add the permissions mentioned here: https://github.com/aws-amplify/amplify-hosting/blob/main/FAQ.md#error-accessdenied-access-denied as well?

philschmid avatar Dec 15 '22 21:12 philschmid

You don't need those permissions anymore if you're deploying Next 13. That documentation is outdated, unfortunately. We need to update that.

calavera avatar Dec 15 '22 22:12 calavera

Thank you for letting me know! I assume those are not longer needed due to the "Trust relationship" which is added?

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "amplify.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Correct? so the "custom" role needs those

philschmid avatar Dec 16 '22 07:12 philschmid

correct. The custom role needs that trust relationship.

calavera avatar Dec 16 '22 17:12 calavera

No success yet. I created an IAM role with CDK

   // create iam role for amplify
    const role = new iam.Role(this, 'AmplifyRole', {
      assumedBy: new iam.ServicePrincipal('amplify.amazonaws.com'),
    });
    // add permissions to write logs
    role.addToPolicy(new iam.PolicyStatement({
      actions: ['logs:CreateLogStream','logs:CreateLogGroup','logs:DescribeLogGroups','logs:PutLogEvents'],
      resources: ['*'],
    }));
    // add permissions to create users in table
    table.grantReadWriteData(role)

which gets successfully created and and permissions seems to be correct. But then inside my Amplify NextJS app I get the following error

Could not load credentials from any providers {
--
message: 'Could not load credentials from any providers',
stack: 'CredentialsProviderError: Could not load credentials from any providers\n' +
'    at /var/task/node_modules/@aws-sdk/credential-provider-node/dist-cjs/defaultProvider.js:13:11\n' +
'    at /var/task/node_modules/@aws-sdk/property-provider/dist-cjs/chain.js:11:28\n' +
'    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
'    at async coalesceProvider (/var/task/node_modules/@aws-sdk/property-provider/dist-cjs/memoize.js:14:24)\n' +
'    at async SignatureV4.credentialProvider (/var/task/node_modules/@aws-sdk/property-provider/dist-cjs/memoize.js:33:24)\n' +
'    at async SignatureV4.signRequest (/var/task/node_modules/@aws-sdk/signature-v4/dist-cjs/SignatureV4.js:86:29)\n' +
'    at async /var/task/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:16:18\n' +
'    at async /var/task/node_modules/@aws-sdk/middleware-retry/dist-cjs/retryMiddleware.js:27:46\n' +
'    at async /var/task/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:5:22\n' +
'    at async getUserByAccount (/var/task/node_modules/@next-auth/dynamodb-adapter/dist/index.js:59:26)',
name: 'CredentialsProviderError'
}

I am trying to use the @aws-sdk/lib-dynamodb in an api/ function. with

const config: DynamoDBClientConfig = {
  region: process.env.NEXT_AUTH_AWS_REGION,
};

const client = DynamoDBDocument.from(new DynamoDB(config), {
  marshallOptions: {
    convertEmptyValues: true,
    removeUndefinedValues: true,
    convertClassInstanceToMap: true,
  },
})

the repository is public as well: https://github.com/philschmid/aws-marketplace-example/blob/main/app/pages/api/auth/%5B...nextauth%5D.ts#L8

philschmid avatar Dec 16 '22 19:12 philschmid

I've been reviewing this with the team, and it might actually not work, and I was wrong 🤦 The role that you setup in our Console is not the same role that the function gets execution credentials from. So the permissions won't be propagated as expected.

So the only solution for now is to inject the credentials in the environment. We're going to look if we can prioritize this work in the near future, but we cannot make any commitments at the moment.

calavera avatar Dec 16 '22 20:12 calavera

Thank you for the response! Too bad it is not working. Adding secrets as an environment doesn't sound super secure or something you should do. I hope you ll find time to add it.

philschmid avatar Dec 16 '22 21:12 philschmid

@philschmid may be a dumb question but, did you import the DynamoDB Table with amplify import storage command and afterward amplify push?

Or did you create a new DynamoDB Table with amplify add storage?

williamrjribeiro avatar Jan 19 '23 23:01 williamrjribeiro

@williamrjribeiro i am not using the amplify cli or amplify functions. I am using CDK/Cloudformation to create everything and then only have a "NextJS" app, where the NextJS functions/api are -> amplify hosting.

philschmid avatar Jan 20 '23 08:01 philschmid

I shall +1 this.

To the dot, the exact same problem is happening, forcing the team to potentially "hardcode" credentials.

nstankov-bg avatar Feb 09 '23 18:02 nstankov-bg

+1 Thank you!

smilhas avatar Feb 25 '23 14:02 smilhas

+1 any news about this? This is very important to secure ssr apps using iam

eezdev avatar Apr 07 '23 15:04 eezdev

Same problem here, is there a plan to fix this by any chance?

GabrieleMazzola avatar Apr 19 '23 09:04 GabrieleMazzola

+1, seems a pretty basic thing to have.

jcmartinezdev avatar May 22 '23 11:05 jcmartinezdev

I know this is not the best solution, but we can generate .env file with IAM user credential in Build process as workaround:

# environment variables config
DUMMY_PREFIX_AWS_ACCESS_KEY_ID = YourAccessKey
DUMMY_PREFIX_AWS_SECRET_ACCESS_KEY = YourSecret
        build:
          commands:
            - env | sed "s/DUMMY_PREFIX_//g" >> .env.production
            - yarn run build

Lagyu avatar May 23 '23 04:05 Lagyu

+1 Since Amplify Hosting can manage multiple stages, we are hoping to implement an IAM Role that can be assigned to each stage.

Currently, as mentioned in the above comment, we cannot find a way other than embedding the access key and secret access key in the environment variables and build of amplify. but this would be difficult to use, especially in a production. because it is a persistent authentication information.

AkihiroTakamura avatar May 24 '23 23:05 AkihiroTakamura

+1 currently using .env.production workaround…

HA55EHH avatar Jun 08 '23 15:06 HA55EHH

I know this is not the best solution, but we can generate a .env file with IAM user credential in Build process as workaround:

# environment variables config
DUMMY_PREFIX_AWS_ACCESS_KEY_ID = YourAccessKey
DUMMY_PREFIX_AWS_SECRET_ACCESS_KEY = YourSecret
        build:
          commands:
            - env | sed "s/DUMMY_PREFIX_//g" >> .env.production
            - yarn run build

This works, but would be cool to not expose my credentials in the Amplify console

Neo-Ciber94 avatar Jun 23 '23 21:06 Neo-Ciber94

Having the same issues here as well Really don't like the workaround 😕

dannyk08 avatar Jul 17 '23 18:07 dannyk08

Any update on this?

KylerD avatar Jul 21 '23 11:07 KylerD

Oh my. Finally found this We have exactly the same issue Using DynamoDB to render some SSR content and @aws-sdk/client-dynamodb does not see the service role past build stage. Our SRE team will not allow us to set credentials in the environment variables for sure. Is there any workaround?

sfedorov-at-wiley avatar Jul 25 '23 20:07 sfedorov-at-wiley

@sfedorov-at-wiley i switched to sst. https://docs.sst.dev

There you have full control since you will create a real lambda function which is not abstracted.

philschmid avatar Jul 25 '23 21:07 philschmid

Or if you don’t like SST you can also use CDK with OpenNext https://github.com/jetbridge/cdk-nextjs

MaxiMittel avatar Jul 25 '23 21:07 MaxiMittel

Following this thread. I guess the only workaround is to use other hosting besides Amplify or set the env variable?

KevinNha avatar Sep 07 '23 04:09 KevinNha

I had the same issue where credentials were stored as env variables. The way I worked around the issue is to store the credentials in AWS secrets manager, and creating an env variable which just holds the secret id . The secret access policy was set to allow 'read' access only to the amplify pipeline service role, so that no one else can see the credentials. During the build, the amplify pipeline fetches those credentials and adds them to .env

yb1727 avatar Sep 10 '23 22:09 yb1727

would be great not to create an IAM user just to have for the Access and Secret Key. is there any updates on this? Thanks is advance

antondelpiero avatar Oct 09 '23 09:10 antondelpiero

any update on this?

LightandSound avatar Oct 19 '23 15:10 LightandSound

Spent days and found the root cause here. Please share some progress or let us know how to vote to accelerate this feature request. Thank you.

kaito-hao avatar Nov 01 '23 22:11 kaito-hao