Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IAM permission with NextJS #3205

Open
4 tasks done
philschmid opened this issue Dec 15, 2022 · 66 comments
Open
4 tasks done

IAM permission with NextJS #3205

philschmid opened this issue Dec 15, 2022 · 66 comments
Labels
compute feature-request New feature or request

Comments

@philschmid
Copy link

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 philschmid added the question Further information is requested label Dec 15, 2022
@philschmid
Copy link
Author

cc @hloriana

@calavera
Copy link
Contributor

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

@philschmid
Copy link
Author

@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?

@calavera
Copy link
Contributor

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

@philschmid
Copy link
Author

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

@calavera
Copy link
Contributor

correct. The custom role needs that trust relationship.

@philschmid
Copy link
Author

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

@calavera
Copy link
Contributor

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.

@philschmid
Copy link
Author

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.

@williamrjribeiro
Copy link

@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?

@philschmid
Copy link
Author

@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.

@nstankov-bg
Copy link

I shall +1 this.

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

@smilhas
Copy link

smilhas commented Feb 25, 2023

+1 Thank you!

@eezdev
Copy link

eezdev commented Apr 7, 2023

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

@GabrieleMazzola
Copy link

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

@bajcmartinez
Copy link

+1, seems a pretty basic thing to have.

@Lagyu
Copy link

Lagyu commented May 23, 2023

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

@AkihiroTakamura
Copy link

+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.

@ghost ghost added the compute label May 26, 2023
@HA55EHH
Copy link

HA55EHH commented Jun 8, 2023

+1 currently using .env.production workaround…

@Neo-Ciber94
Copy link

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

@dannyk08
Copy link

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

@KylerD
Copy link

KylerD commented Jul 21, 2023

Any update on this?

@sfedorov-at-wiley
Copy link

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?

@philschmid
Copy link
Author

@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.

@MaxiMittel
Copy link

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

@KevinNha
Copy link

KevinNha commented Sep 7, 2023

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

@yb1727
Copy link

yb1727 commented Sep 10, 2023

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

@antondelpiero
Copy link

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

@callumthomson
Copy link

I've been trying to solve this exact same issue for quite some time now and have landed here. From what I have read, it seems like there is no proper way to grant IAM permissions to the server side of my NextJS app hosted in Amplify. This is definitely something that is absolutely crucial to have.

@webdesignbystephen
Copy link

July 2024: Still annoying developers!

@triwonderdigital
Copy link

triwonderdigital commented Aug 6, 2024

From the docs here: https://docs.aws.amazon.com/amplify/latest/userguide/ssr-environment-variables.html I have these set:

version: 1 frontend: phases: preBuild: commands: - npm ci --cache .npm --prefer-offline build: commands: - npm run build - env | grep -e NEXT_PUBLIC_API_DOMAIN >> .env.production - env | grep -e ACCESS_KEY_ID >> .env.production - env | grep -e SECRET_ACCESS_KEY >> .env.production - env | grep -e REGION >> .env.production artifacts: baseDirectory: .next files: - '**/*' cache: paths: - .next/cache/**/* - .npm/**/*

After checking the logs we see: CredentialsProviderError: Could not load credentials from any providers
This is the same issue as part of this ticket? OK after spending 3 days going round in circles trying to get our app running with server api. I decided to try Vercel up and running with no errors in 10 minutes, bye bye amplify...

@hans25041
Copy link

This is critical. We've been trying to transition away from persistent credentials and IAM users for a long time. It's surprising to me that a modern, serverless Amazon service would encourage (require?) the use of long term credentials. There should be an execution role that the NextJS app uses when it runs. I'm too invested to move my current project away from Amplify, but I won't recommend that my company uses Amplify again until this problem is solved. I know AWS likes to say that "security is job #1." That means that this should be a top priority.

@HoltSpalding
Copy link

Bump

@Pito1992
Copy link

Pito1992 commented Sep 1, 2024

Hello guys,

I faced a similar situation and here was my solution. The solution suits my case but I think I may fit your side or anybody else, and I'm happy if it can help.
I was a person like you who was looking for a solution in StackOverflow; GitHub issues; I tried to modify the AWS IAM policy, role... but there was no luck.
Then, I was reading back to the AWS Amplify documents carefully and this link below was the savior. It took me 2 days to recognize this one. Honestly, AWS Amplify documents are not clear enough and its search results are stupid.
https://docs.amplify.aws/react/build-a-backend/add-aws-services/geo/amazon-location-sdk/

Regarding the link, it requires you to attach credentials to any AWS-SDK you want to use rather than using the local AWS config. For example, I was using "@aws-sdk/client-iot" and it should be like this

const client = new IoTClient({
    credentials,
    region: env.REGION
 })

In my case, a user should log in to the app and use the services inside so I don't need to set my AWS config by env or secret params. Just create a user pool and manage policies on it.

@gennaroanesi
Copy link

I was open to injecting the secrets as env variables using the ssm cli during build, but that didn't seem to work as well (secrets json is empty for me even though I have them set up in the console)

@Gilaad-Elstein
Copy link

Gilaad-Elstein commented Sep 16, 2024

I was open to injecting the secrets as env variables using the ssm cli during build, but that didn't seem to work as well (secrets json is empty for me even though I have them set up in the console)

Have you tried this approach? Until we get IAM support this is the best way I found with Amplify and NextJS. It is a deal breaker for some projects for sure, but it does work. Just mind what you expose on server and client side, on the console etc.

@mauerbac
Copy link
Member

Hello - this issue has now been moved to in-development! We are looking at a solution where you would create an IAM role and then have the ability to attach that role within the Amplify Hosting console.

I'm curious what types of roles/policies folks want to attach? What is the use case? What will the policies do?

Thank you!

@moesmufti
Copy link

Hello - this issue has now been moved to in-development! We are looking at a solution where you would create an IAM role and then have the ability to attach that role within the Amplify Hosting console.

I'm curious what types of roles/policies folks want to attach? What is the use case? What will the policies do?

Thank you!

For me, one role/policy that I would like to attach is dynamoDB access. This would allow the serverless app to modify the DB (without forcing env variables) upon verified conditions.

@webdesignbystephen
Copy link

webdesignbystephen commented Sep 25, 2024 via email

@lyleunderwood
Copy link

I'm curious what types of roles/policies folks want to attach? What is the use case? What will the policies do?

I am currently injecting an access key via env vars so that my next app can talk to DynamoDB which is currently managing sessions (lucia/arctic).

@mauerbac
Copy link
Member

One more question for feedback, please --

Would folks want the IAM permissions to apply at the branch or app level? meaning, if app level all branches would have access to the same IAM role credentials

@kaito-hao
Copy link

To us, app level would be sufficient, we deploy one app per each stage (dev, beta, etc). But no harm to have more granular (branch level) control, if the configuration is easy to understand and to deploy.

@lyleunderwood
Copy link

We currently do the same.

@dkandlyk
Copy link

dkandlyk commented Nov 1, 2024

Hi Matt!

We prefer it to be on a branch level since we have some long-lived branches for testing and internal use. This would enable us to assign different permissions to those branches. :)

@mauerbac
Copy link
Member

mauerbac commented Nov 1, 2024

Thank you, everyone. It looks like we are going with an App level IAM role with the ability for branch level overrides :)

@Seikilos
Copy link

Seikilos commented Nov 13, 2024

Is there an ETA for this? If it will take some time (which is ok), I will outsource all credential stuff into an lambda function behind API. If the fix is expected to be production ready in weeks, I will plan differently.

Btw my use case: Need SES from Svelte SSR to send some email and would really prefer not to use long term credentials. But exposing SES via a public API is probably also a bad idea :/

@mmtvarela
Copy link

I'm facing the same problem, would appreciate any updates

@meryemben92
Copy link

meryemben92 commented Nov 20, 2024

Hello,

I implemented the following workaround in my Amplify build settings to extract AWS credentials from the ~/.aws/credentials file, and it works, I can access now AWS services (dynamodb) within my NextJS app :

build:
  commands:
    - echo "Extracting AWS credentials from ~/.aws/credentials"
    - echo "AWS_ACCESS_KEY_ID=$(grep aws_access_key_id ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SECRET_ACCESS_KEY=$(grep aws_secret_access_key ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SESSION_TOKEN=$(grep aws_session_token ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production

PS: you need to make sure to use the aws session token as Amplify uses temporary credentials

@henryqum
Copy link

Hello,

I implemented the following workaround in my Amplify build settings to extract AWS credentials from the ~/.aws/credentials file, and it works, I can access now AWS services (dynamodb) within my NextJS app :

build:
  commands:
    - echo "Extracting AWS credentials from ~/.aws/credentials"
    - echo "AWS_ACCESS_KEY_ID=$(grep aws_access_key_id ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SECRET_ACCESS_KEY=$(grep aws_secret_access_key ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SESSION_TOKEN=$(grep aws_session_token ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production

PS: you need to make sure to use the aws session token as Amplify uses temporary credentials

Hi @meryemben92
I tested it yesterday and it works but this morning my app stop working as it was not able to access to aws as the session expired, how do you handle it?

@lahiiru
Copy link

lahiiru commented Dec 19, 2024

Hello,
I implemented the following workaround in my Amplify build settings to extract AWS credentials from the ~/.aws/credentials file, and it works, I can access now AWS services (dynamodb) within my NextJS app :

build:
  commands:
    - echo "Extracting AWS credentials from ~/.aws/credentials"
    - echo "AWS_ACCESS_KEY_ID=$(grep aws_access_key_id ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SECRET_ACCESS_KEY=$(grep aws_secret_access_key ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production
    - echo "AWS_SESSION_TOKEN=$(grep aws_session_token ~/.aws/credentials | awk -F'=' '{print $2}')" >> .env.production

PS: you need to make sure to use the aws session token as Amplify uses temporary credentials

Hi @meryemben92 I tested it yesterday and it works but this morning my app stop working as it was not able to access to aws as the session expired, how do you handle it?

This works immediately after an deployment. But I don't think this is a solution. The token get expired after sometime.
Error creating evaluation task: ExpiredToken: The provided token has expired.

@hunganhAtWhill
Copy link

hunganhAtWhill commented Dec 25, 2024

Another potential workaround, is to create a IAM User with approriate permission set (for example in my case, i want to access Secrets Manager, so I assigned SecretsManagerReadAndWrite). After, you create AccessKey for that user, and inject those to nexjts app using Amplify Secrets Environmental Variables tab.

@JoseSpx
Copy link

JoseSpx commented Dec 27, 2024

having the same problem here! please any update how to fix it using roles and note hardcoding secrets in the env variables?

@lahiiru
Copy link

lahiiru commented Dec 27, 2024

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

@JoseSpx
This is the only solution worked for me. Please check below points, if you don't know how this works

  • DUMMY_PREFIX_ is added because amplify does not let you to add env variables starts with AWS.
  • At the time of building this approach packages the backend release with .env.production file with hardcoded AWS credentials.
  • You do not need to hard code environmental variables in source code. Go to Amplify using AWS console and put those in the Hosting > Environment variables section.
  • When you are creating the AWS credentials, create an IAM user. Then assign required additional roles to the user. Remember to assign the existing role or policy also. Then create access keys for that IAM user. You can see the existing role from App settings > General settings > Service Role

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compute feature-request New feature or request
Projects
Development

No branches or pull requests