Cant set AWS credentials in nodejs - node.js

I'm working on a cloud project using NodeJS.
I have to run EC2 instances so have done a npm install aws-sdk.
I believe we have to add our credentials now before we run the application?
I could not aws folder so I have created a folder and added the credentials in the credentials.txt file.
C:\Users\jessig\aws
I keep getting this error:
{ [TimeoutError: Missing credentials in config]
message: 'Missing credentials in config',
code: 'CredentialsError',
I tried setting the Access key and secret key in environment variables but still get the same error..
Not sure why I cant find the \.aws\credentials (Windows) folder..
Can anyone please help?

As Frederick mentioned hardcoding is not an AWS recommended standard, and this is not something you would want to do in a production environment. However, for testing purpose, and learning purposes, it can be the simplest way.
Since your request was specific to AWS EC2, here is a small example that should get you started.
To get a list of all the methods available to you for Node.js reference this AWS documentation.
var AWS = require('aws-sdk');
AWS.config = new AWS.Config();
AWS.config.accessKeyId = "accessKey";
AWS.config.secretAccessKey = "secretKey";
AWS.config.region = "us-east-1";
var ec2 = new AWS.EC2();
var params = {
InstanceIds: [ /* required */
'i-4387dgkms3',
/* more items */
],
Force: true
};
ec2.stopInstances(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});

I used the following programmatic way, combined with the popular npm config module (which allows different config files for development vs production, etc.):
const config = require('config');
const AWS = require('aws-sdk');
const accessKeyId = config.get('AWS.accessKeyId');
const secretAccessKey = config.get('AWS.secretAccessKey');
const region = config.get('AWS.region');
AWS.config.update(
{
accessKeyId,
secretAccessKey,
region
}
);
And the json config file, e.g. development.json, would look like:
{
"AWS": {
"accessKeyId": "TODO",
"secretAccessKey": "TODO",
"region": "TODO"
}
}

There are multiple ways to configure the sdk to work with node js
There are a few ways to load credentials. Here they are, in order of
recommendation:
Loaded from IAM roles for Amazon EC2 (if running on EC2),
Loaded from the shared credentials file (~/.aws/credentials),
Loaded from environment variables,
Loaded from a JSON file on disk,
Hardcoded in your application
Although the hardcoded one is not recommended.
If you want to use a shared credentials files, on windows it would be
C:\Users\jessig\.aws\credentials
(note the . before aws). Your file should be something like
[default]
aws_access_key_id = your_access_key
aws_secret_access_key = your_secret_key

Adding accessKeyId and secretAccessKey in the config for AWS is deprecated as of today. As the AWS Docs for SDK for Node.js states:
The SDK automatically detects AWS credentials set as variables in your environment and uses them for SDK requests. This eliminates the need to manage credentials in your application. The environment variables that you set to provide your credentials are:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN (Optional)
https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html
You may want to use dotenv package to load those environment variables.

The AWS credentials can be set as ENVIRONMENT VAR in the running container.
You would either add the following two ENVIRONMENT VAR directly:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
or set these ENVIRONMENT VAR programmatically within NODE as
var AWS = require('aws-sdk')
AWS.config = new AWS.Config();
process.env.AWS_ACCESS_KEY_ID = "AKIA************L55A"
process.env.AWS_SECRET_ACCESS_KEY = "Ef*******+C5LrtOroSj**********yNE"
AWS.config.region = "us-east-2"
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/loading-node-credentials-environment.html

Related

React javascript "Error: Credential is missing" when connecting to DynamoDBClient

I'm trying to connect to my dynamoDB table from inside a React js app. I have AWS credentials set up locally. When I run my app, I get the following error on Chrome Devtools: "Error: Credential is missing".
Oddly, if I run the AWS example found below using pretty much the same code via node on terminal, it works fine. https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javascriptv3/example_code/dynamodb/src/partiQL_examples/src/partiql_getItem.js
To run the AWS example, I created a new mjs file inside my react SRC folder, so it should have all the same access as the React app, right? No credentials are explicitly added in the mjs file or the react app.
Why doesn't the React environment have access to the credentials? I've tried both ~/.aws/credentials and environment variables. The AWS SDK seems to say that it should just work for Node. Any thoughts?
import { DynamoDBClient, ExecuteStatementCommand} from '#aws-sdk/client-dynamodb';
function App() {
const dynamoDB = new DynamoDBClient({ region : "us-west-2"});
async function loadFromCloud () {
const command = new ExecuteStatementCommand({
Statement: `select * from TableX`
});
try {
const data = await dynamoDB.send(command);
console.log(data);
} catch (error) {
console.log(error);
}
}
Make sure that you have AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY specified as environment variables and that you also specify AWS_SDK_LOAD_CONFIG=1
However, your React app is run in the browser. It should only work in a node.js app.

I get "ConfigError: Missing region in config" when I use AWS SES to send an email

I'm using node and next js.
I wrote a function to send an email when someone subscribes to a newsletter; it sends a welcome email. The error comes out when I call the function.
In terms of what I tried to fix this credentials problem:
I used the "aws configure" command that the aws cli provides.
I used a .env file with the credentials.
I set the enviroment variables on my pc via the set command (this did set them up but I still have the problem).
Currently I'm using this on top of my function (I'm trying to make it work with the .env file):
var AWS = require("aws-sdk")
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.SECRET_ACCESS_KEY,
region: process.env.AWS_REGION
})
Something that might be useful is that when I use console.log to log out the enviroment variables the result is "undefined". I tested it out with another enviroment variable (NODE_ENV) and it does come out correctly.

How to approach use of environment variables for Lambda#Edge

I'm building Lambda function for CloudFront which checks if request has cookies, if not then forwards to login page. I need to customize response header location based on environment - for each env that will be different.
Initially I tried with environment variables but I got an error during deployment:
InvalidLambdaFunctionAssociation: The function cannot have environment variables
So I switched to use aws-sdk with SSM ssm.getParameter but after zipping lambda archive with aws-sdk and one more depedency it's around 13 MB. The limit for Lambda#Edge functions is 1 MB.
I'm wondering would be the best way to approach that. Generate file with environment variables on each Lambda build and require it in index.js?
Use SSM but don't include AWS SDK in your Lambda function. Lambda documentation says that the AWS SDK is included in the Lambda runtime.
To test this, I created a new Node.js 12 Lambda function from scratch in the Lambda console & replaced its existing code with this:
const AWS = require('aws-sdk');
const SSM = new AWS.SSM();
exports.handler = async() => {
return {
statusCode: 200,
body: await SSM.getParameter({ Name: 'my-param' }).promise(),
};
};
This works! Downloading the deployment package of this function from the Lambda console showed that it's just 276 bytes in size. I then deployed this to Lambda#Edge & that worked too!

Failed attempts to write to DynamoDB Local

I recently discovered DynamoDB Local and started building it into my project for local development. I decided to go the docker image route (as opposed to the downloadable .jar file.
That being said I've gotten image up and running and have created a table and can successfully interact with the docker container via the aws cli. aws dynamodb list-tables --endpoint-url http://localhost:8042 successfully returns the table I created previously.
However, when I run my lambda function and set my aws config like so.
const axios = require('axios')
const cheerio = require('cheerio')
const randstring = require('randomstring')
const aws = require('aws-sdk')
const dynamodb = new aws.DynamoDB.DocumentClient()
exports.lambdaHandler = async (event, context) => {
let isLocal = process.env.AWS_SAM_LOCAL
if (isLocal) {
aws.config.update({
endpoint: new aws.Endpoint("http://localhost:8042")
})
}
(which I have confirmed is getting set) it actually writes to the table (with the same name of the local dynamodb instance) in the live AWS Webservice as opposed to the local container and table.
It's also worth mentioning I'm unable to connect to the local instance of DynamoDB with the AWS NoSQL Workbench tool even though it's configured to point to http://localhost:8042 as well...
Am I missing something? Any help would be greatly appreciated. I can provide any more information if I haven't already done so as well :D
Thanks.
SDK configuration changes, such as region or endpoint, do not retroactively apply to existing clients (regular DynamoDB client or a document client).
So, change the configuration first and then create your client object. Or simply pass the configuration options into the client constructor.

aws s3 node js sdk method generatePutUrl returns differnt results for localhost and deployment on heroku

I am trying to manage direct file upload to S3 according to heroku recomendations
first one need to generate presigned URL at ones server
use this url in client to direct upload of image from browser to S3 bucket
and finally manage to works it locally.
but when I tried to deploy server on heroku it starts to fail with no reason or readable error. Just common error and strange message when I try to print it
what looks strange for me that presigned urls are completely different when I make call from local host or from heroku
response for localhost looks like this:
https://mybucket.s3.eu-west-1.amazonaws.com/5e3ec346d0b5af34ef9dfadf_avatar.png?AWSAccessKeyId=<AWSKeyIdHere>&Content-Encoding=base64&Content-Type=image%2Fpng&Expires=1581172437&Signature=xDJcRBiA%2FmQF1qKhBZrnhFXWdaM%3D
and response for heroku deployment looks like this:
https://mybucket.s3.u-west-1.amazonaws.com/5e3ee2bd1513b60017d85c6c_avatar.png?Content-Type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<credentials-key-here>%2F20200208%2Fu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20200208T163315Z&X-Amz-Expires=900&X-Amz-Signature=<someSignature>&X-Amz-SignedHeaders=content-encoding%3Bhost
server code is almost like in examples:
const Bucket = process.env.BUCKET_NAME
const region = process.env.BUCKET_REGION
AWS.config = new AWS.Config({
accessKeyId: process.env.S3_KEY,
secretAccessKey: process.env.S3_SECRET,
region,
logger: console
})
const s3 = new AWS.S3()
async function generatePutUrl(inputParams = {}) {
const params = { Bucket, ...inputParams }
const { Key } = inputParams
const putUrl = await s3.getSignedUrl('putObject', params)
const getUrl = generateGetUrlLocaly(Key)
return {putUrl, getUrl}
}
the only difference that I can imagine is SSL - I run local server VIA http and heroku goes over https by default...
but I don't understand how it may influence here.
I will appreciate any meaningful advises how to debug and fix it.
thank you.
It looks like that your bucket region is incorrect. Shouldn't it be eu-west-1 instead of u-west-1?
Please update your BUCKET_REGION in environment variables at Heroku Server settings from
u-west-1
to
eu-west-1
and restart the dynos. It may solve your problem.

Resources