Search code examples
node.jsaws-lambdaamazon-cloudwatchserverless-framework

Unable to retrieve cloudWatch GetMetricData in Nodejs application


I need to get MetricData in Node.js application for my AWS Lambda enter image description here

Error received:

AccessDenied: User: arn:aws:sts::123456789012:assumed-role/dev-rohit-ap-southeast-1-lambdaRole/dev-rohit-uploader is not authorized to perform: cloudwatch:GetMetricData\n    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/query.js:50:29)\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)\n    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)\n    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)\n    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)\n    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)\n    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12)\n    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)

Serverless.yaml

- Effect: "Allow"
      Action:
        - "lambda:GetMetricData"
      Resource: arn:aws:lambda:${self:custom.region}:${self:custom.accountId}:function:${self:service}-${opt:stage}-uploader

Getting Metric Data function

exports.getMetrics = async () => {
  const params = {
    EndTime: '2021-09-07T03:04:00Z',
    MetricDataQueries: [
      {
        Id: 'concurrencycount',
        Label: 'Average concurrency',
        MetricStat: {
          Metric: {
            Dimensions: [
              {
                Name: 'upload',
                Value: process.env.S3_UPLOAD_BUCKET
              },
            ],
            MetricName: 'Invocations',
            Namespace: 'AWS/Lambda'
          },
          Period: '300',
          Stat: 'Average',
          Unit: 'Count'
        },
        ReturnData: false
      },
    ],
    StartTime: '2021-09-07T03:01:00Z',
    //ScanBy: TimestampDescending
  };

  try {
    return await client().getMetricData(params).promise()
  } catch (error) {
    logger.error(error, 'Error getting metrics from Lambda Cloudwatch')
    throw error
  }
}

What I tried :

  1. Updated Action in serverless.yaml

    Action:

    • "cloudwatch:GetMetricData"
  2. Updated ARN to

    Resource: arn:aws:lambda:${self:custom.region}:${self:custom.accountId}:function:${self:service}-${opt:stage}-uploader

  3. Updated

    Resource: arn:aws:logs:${self:custom.region}:${self:custom.accountId}:log-group:/aws/lambda/${self:service}-${opt:stage}-uploader:*

didn't work.

Resources: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CloudWatch.html#getMetricData-property

Can someone please help me?


Solution

  • You have to set the Resource to * and use condition keys to limit the access scope:

    https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/iam-cw-condition-keys-namespace.html

    So your policy statement might look something like:

    - Effect: "Allow"
          Action:
            - "cloudwatch:GetMetricData"
          Resource: "*"
          Condition:
             StringEquals:
                 "cloudwatch:namespace": "AWS/Lambda"