9

I am developing an application where I need to schedule a task, so I am using AWS Lambda for it.However, the scheduled time is dynamic, since it depends on the user request, it can't be scheduled using AWS Console, so I use AWS Javascript SDK to schedule it. This is the flow:

  1. Create a CloudWatch Rule (this is successful, I can see the rule being created in the console
  2. Add permission to the policy of lambda, so that cloudwatch event can invoke it (Lambda function code is same for all request, so I created a lambda function in AWS Console instead of using SDK)
  3. Add target to the rule created in Step 1 (this step fails). The error i get is RoleArn is not supported for target arn:aws:lambda:eu-west-1:629429065286:function:prebook.

Below is the Node.js code I wrote

schedule_aws_lambda: function(booking_id, cronTimeIST, callback){
      var event = new AWS.CloudWatchEvents({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey,
        region: 'eu-west-1'
      });

      var lambda = new AWS.Lambda({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey,
        region: 'eu-west-1'
      });

      var year = cronTimeIST.utc().year();
      var month = cronTimeIST.utc().month() + 1;
      var date = cronTimeIST.utc().date();
      var hour = cronTimeIST.utc().hour();
      var minute = cronTimeIST.utc().minute();
      var cronExpression = "cron(" + minute + " "+ hour + " " + date + " " + month + " ? " + year +")";
      var hour_minute = cronTimeIST.format("HH_mm");
      var ruleParams = {
        Name: 'brodcast_' + booking_id + '_' + hour_minute,
        Description: 'prebook brodcast for ' + booking_id + '_' + hour_minute,
        ScheduleExpression: cronExpression, 
        RoleArn: 'arn:aws:iam::629429065286:role/service-role/prebook_lambda_role',
        State: 'ENABLED',
      };
      event.putRule(ruleParams).promise()
      .then(data => {
        var lambdaPermission = {
          FunctionName: 'arn:aws:lambda:eu-west-1:629429065286:function:prebook',
          StatementId: 'brodcast_' + booking_id + '_' + hour_minute,
          Action: 'lambda:*',
          Principal: 'events.amazonaws.com', 
        };
        return lambda.addPermission(lambdaPermission).promise();
      })
      .then(data => {
        var targetParams = {
          Rule: ruleParams.Name,
          Targets: [
            {
              Id: 'default',
              Arn: 'arn:aws:lambda:eu-west-1:629429065286:function:prebook',
              RoleArn: ruleParams.RoleArn,
              Input: JSON.stringify({booking_id: booking_id})
            }
          ]
        };
        return event.putTargets(targetParams).promise();
      })
      .then(data => {
        callback(null, data);
      })
      .catch(err => {
        callback(err)
      });  
    }

I know it has to do something with the Role which doesn't have some permission, I can't figure out the exact cause, I have given the following access for the role enter image description here

And this is the policy document

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Basically, I want to attach many triggers(the trigger time is not known to me it depends on user request) to the lambda function, however, lambda function code is same for all.

vikneshwar
  • 597
  • 1
  • 6
  • 17
  • Did you ever get anywhere with this? – Joseph Carroll Jul 28 '17 at 16:50
  • No, currently we are scheduling with node-cron instead of lambda , however, that's not the right way, since cron schedule will be lost if the server crashes or restarts. We are trying alternative solutions like Firebase cloud functions and Firebase DB. – vikneshwar Jul 30 '17 at 20:35

2 Answers2

21

Try removing the RoleArn property. If you are adding permissions to the Lambda function to allow CloudWatch events to invoke it, you don't need it.

In the function policy, make sure you add the SourceArn of the event.

user1607158
  • 478
  • 1
  • 4
  • 12
  • 2
    Thanks, I wasted hours to figure out this trouble and adding permission to the lambda function (using `Lambda.addPermission`) fixed it. – Tien Do Sep 10 '19 at 09:22
  • I was able to use the aws cli SDK to add the permission like it is outlined here: https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/CWE_Troubleshooting.html#LAMfunctionNotInvoked – Noah Gary Nov 05 '21 at 17:58
  • Here is the example adding permission using AWS SAM https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-use-sam.html – Wen Feb 15 '22 at 02:01
  • Try disabling and enabling the event rule. In my case, I 1) created the event rule through CloudFormation with proper IAM RoleARN for the rule (with assume role), for an EXISTING lambda function. 2) Then granted permission through aws cli as above. Rule did not run and no error. 3) Disabled and Enabled rule through console it started firing on schedule. – Charles Letcher Mar 07 '22 at 16:03
1

Here's the reference from the docs that explains the error. You must use a resource policy (= Lambda permission), not an identity policy (= role) to invoke Lambda from EventBridge:

Docs: Amazon SQS, Amazon SNS, Lambda, CloudWatch Logs, and EventBridge bus targets do not use roles, and permissions to EventBridge must be granted via a resource policy. API Gateway targets can use either resource policies or IAM roles.

The Lambda AddPermission API creates the resource policy.

fedonev
  • 20,327
  • 2
  • 25
  • 34