How to manage secrets for a NextJS 14 app built and hosted via Amplify

0

I am deploying and hosting a NextJS 14 app using AWS Amplify Console tied to a repo. I plan to attach a custom domain. I am not using Amplify CLI. I am using Simple Email Service, via @aws-sdk/client-ses, to send content from a form in the Next app to a registered email account. To utilize SES, I need to manage AWS secrets. In the past, I leveraged SES via Lambdas, but here I am using NextJS's server actions and the AWS SDK SES client. Everything works in my local instance, and as I move to production and host this in Amplify, I want to take the proper security measures for the secrets.

What I have gathered from several hours of research:

  1. I can store secrets under Hosting > Secrets from within the app/project in Amplify Console. That should be a legitimate, secure approach, but I am not sure how to access from there within my server-side code.
  2. I could also store secrets using Secret Manager, and then perhaps I could use the SecretsManagerClient in the Javascript v3 SDK to access the needed secrets from the server-side JS logic??

I have not determined a clear, secure process to follow for managing secrets for the NextJS app and Amplify Console. Some people have treated secrets like env vars, and I know that is not appropriate.

Could anyone please advise on a secure, standard way of managing and accessing secrets in this context?

1 Answer
0

1. Using AWS Secrets Manager

AWS Secrets Manager is a secure and scalable service to store and manage secrets.

Steps to use AWS Secrets Manager:

1. Store Secrets in AWS Secrets Manager:

Navigate to the AWS Secrets Manager console.

Create a new secret and enter the secret values (e.g., your SES credentials).

Save the secret and note down the secret ARN.

2. Grant Permissions:

Ensure your Amplify app has the necessary permissions to access the secrets stored in AWS Secrets Manager. You can achieve this by attaching an appropriate IAM role or policy to your Amplify backend environment.

3. Access Secrets in Your NextJS App:

Install the AWS SDK in your NextJS app:

       npm install @aws-sdk/client-secrets-manager

Use the following code in your server-side actions to retrieve the secrets:

import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";

const client = new SecretsManagerClient({ region: "your-region" });

async function getSecretValue(secretName) {
  try {
    const command = new GetSecretValueCommand({ SecretId: secretName });
    const response = await client.send(command);
    return JSON.parse(response.SecretString);
  } catch (error) {
    console.error("Error retrieving secret:", error);
    throw error;
  }
}

// Example usage
export async function sendEmail() {
  const secret = await getSecretValue("your-secret-name");
  const sesClient = new SESClient({
    region: "your-region",
    credentials: {
      accessKeyId: secret.AWS_ACCESS_KEY_ID,
      secretAccessKey: secret.AWS_SECRET_ACCESS_KEY,
    },
  });

  // Use the sesClient to send an email
}

Using Amplify Console Secrets

Amplify Console provides a way to store secrets, which can then be accessed as environment variables.

Steps to use Amplify Console Secrets:

1. Store Secrets in Amplify Console:

Go to your Amplify app in the Amplify Console.

Navigate to the Environment variables section under Build settings.

Add your secrets as environment variables.

2. Access Environment Variables in Your NextJS App:

NextJS allows you to access environment variables through the process.env object.

3. Use the environment variables in your server-side actions:

import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";

const sesClient = new SESClient({
  region: process.env.AWS_REGION,
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

export async function sendEmail() {
  const command = new SendEmailCommand({
    // email parameters
  });

  try {
    const response = await sesClient.send(command);
    console.log("Email sent successfully:", response);
  } catch (error) {
    console.error("Error sending email:", error);
    throw error;
  }
}
Yasik
answered 7 days ago
  • As I mentioned, I will not use Environment Variables, as it is not a substitute for Secrets.

    I have tried for hours to get the SecretsManagerClient example to work, but I get an error, and it does not provide much detail: Error retrieving secret: i [CredentialsProviderError]: Could not load credentials from any providers

    My secrets are stored in Secrets Manager, and I have confirmed no typos when referencing the secrets. I am not sure if specific IAM permissions are missing and causing this. I have SecretsManagerReadWrite and AmplifyBackendDeployFullAccess as policies attached to the Amplify app.