lazywithclass / winston-cloudwatch

Send logs to Amazon Cloudwatch using Winston.
MIT License
258 stars 104 forks source link

Unable to set aws credentials in v3.2.0 #181

Closed blaxk closed 2 years ago

blaxk commented 2 years ago
const logger = winston.createLogger({
   transports: [
      new WinstonCloudWatch({
         name: `/my-log/${stage}`,
         logGroupName: `/aws/s3/${repoName}`,
         logStreamName: 'log-stream',
         awsRegion: 'ap-northeast-2',
         awsAccessKeyId: stage === 'prod' ? process.env.PROD_ACCESS_KEY_ID : process.env.DEV_ACCESS_KEY_ID,
         awsSecretKey: stage === 'prod' ? process.env.PROD_SECRET_ACCESS_KEY : process.env.DEV_SECRET_ACCESS_KEY
      })
   ]
})

In winston-cloudwatch v3.1.1 with aws-sdk v2 you could set the awsAccessKeyId, awsSecretKey options. However, in winston-cloudwatch v3.2.0 using aws-sdk v3, even setting the awsAccessKeyId and awsSecretKey options causes the credentials error as shown below.

image

You're probably looking at the credentials set in your .aws/credentials file. I want to be able to set the awsAccessKeyId and awsSecretKey in the winston-cloudwatch option, without the .aws/credentials file.

stickchartkeith commented 2 years ago

Just to add additional context here, this is also an issue 4.0.1 - and last worked in 3.1.1 for me. As a workaround, if using Elastic Beanstalk, attaching the Cloudwatch Full policy to the account running Beanstalk got things working again for me.

rgwebcode commented 2 years ago

What is the correct way to set the AWS credentials now? I've tried to create a credentials file in a .aws directory in the root of the project, with the content

[default]
aws_access_key_id=...
aws_secret_access_key=...

As per the AWS documentation, but I still receive the same error (CredentialsProviderError: Could not load credentials from any providers).

And when I tried to go back to 3.1.1, I now receive a The security token included in the request is invalid. error.

rgwebcode commented 2 years ago

Ok, digging more into it, the .aws/credentials file needs to be in the user directory (see this page).

However digging even further, I seem to have found an override for the file path location (found in @aws-sdk/shared-ini-file-loader/dist-es/getCredentialsFilepath.js). You can provide an environment variable called AWS_SHARED_CREDENTIALS_FILE which points to that credentials file. And only if this variable is not set it will default to the user directory and to .aws/credentials.

So setting e.g. AWS_SHARED_CREDENTIALS_FILE=./config/.aws seems to work for providing the AWS info within your node project folder.

I've also found that you could set the credentials directly in your environment variable, with AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, however in this case it also expects an AWS_SESSION_TOKEN (and possibly an AWS_CREDENTIAL_EXPIRATION as well), which you don't seem to be be able to retrieve without somehow authenticating first. So directly setting the AWS credentials in your environment variables (or .env file) is not possible, at least not without further work and/or investigation.

tkdave commented 2 years ago

In our case, we are already using the AWS SDK and AWS_* env vars. We need to specifically pass in values pulled from alternately-named env vars. 3.1.1 works for our needs.

amites commented 2 years ago

this still seems to be an issue in 6.x -- has anyone looked into why to open a pull request?

lazywithclass commented 2 years ago

Sorry for being so late, I managed to get some time to work on this given the time you've been waiting.

I followed this guide but unfortunately I am not able to replicate, so my suspect is that I did not correctly understand the issue here; this is what I am doing:

$ AWS_ACCESS_KEY_ID=? AWS_SECRET_ACCESS_KEY=? node credentials-test.js
const WinstonCloudWatch = require('../index')

const logger = winston.createLogger({
  transports: [
    new WinstonCloudWatch({
     name: `log`,
      logGroupName: `group-name`,
     logStreamName: 'stream-name',
      awsRegion: 'eu-west-2'
   })
 ]
})

logger.error('2');

I got 2 logged in AWS.

amites commented 2 years ago

the issue is that defining the API credentials in the initialization class is ignored

if you have them set within ~/.aws/credentials or the environment it uses them correctly

if that's the direction of then package that's fine, I built a work around that generates the credentials files in docker and I know that assigning roles to the running container is the appropriate runtime solution -- just juggling priority as you do in a startup

yzpaul commented 2 years ago

simple steps to reproduce:

  1. remove default profile from .awsconfig (or rename it)
  2. set credentials to CORRECT VALUES in new WinstonCloudwatch({awsAccessKeyId: 'aaaa', awsSecretKey: 'bbbb'})

Attempt to write a log. Code will fail with error CredentialsProviderError: Could not load credentials from any providers at lib.ensureGroupPresent when it calls aws.describeLogStreams

somehow this is function call is using the default credentials, despite passing in (and tracing) the fact that it is using custom credentials)

yzpaul commented 2 years ago

Submitted pull request to fix the issue: https://github.com/lazywithclass/winston-cloudwatch/pull/192

nikhilrajaram commented 2 years ago

I have been able to circumvent this by specifying the CloudWatchLogsClientConfig directly though awsOptions

new WinstonCloudWatch({
  ...,
  awsOptions: {
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
    region,
  }
})
b0nbon1 commented 2 years ago

I have been able to circumvent this by specifying the CloudWatchLogsClientConfig directly though awsOptions

new WinstonCloudWatch({
  ...,
  awsOptions: {
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
    region,
  }
})

Thanks @nikhilrajaram, It worked for me too

blaxk commented 2 years ago

I have been able to circumvent this by specifying the CloudWatchLogsClientConfig directly though awsOptions

new WinstonCloudWatch({
  ...,
  awsOptions: {
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
    region,
  }
})

Thanks @nikhilrajaram In this way the issue was resolved.

@lazywithclass I would appreciate it if you could edit the README.

lazywithclass commented 2 years ago

Done https://github.com/lazywithclass/winston-cloudwatch/blob/master/README.md#credentials

Thanks for the help everyone, it's much appreciated!

KZTN commented 5 months ago

I have been able to circumvent this by specifying the CloudWatchLogsClientConfig directly though awsOptions

new WinstonCloudWatch({
  ...,
  awsOptions: {
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
    region,
  }
})

this solution works fine. Thanks!