lazywithclass/winston-cloudwatch

Unable to set aws credentials in v3.2.0

Closed this issue ยท 14 comments

blaxk commented
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.

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.

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.

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.

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.

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

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.

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

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)

Submitted pull request to fix the issue: #192

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

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

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

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.

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

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

KZTN commented

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!