Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[aws-events] Rule.addTarget(new LambdaFunction(Function.fromFunctionArn(...))) does not add trigger to Lambda #10509

Closed
dforsber opened this issue Sep 24, 2020 · 16 comments
Labels
@aws-cdk/aws-events Related to CloudWatch Events bug This issue is a bug. effort/medium Medium work item – several days of effort p1

Comments

@dforsber
Copy link

dforsber commented Sep 24, 2020

No trigger on AWS Lambda for Rule Target in different CF Stack

  1. Rule.addTarget(new LambdaFunction(Function.fromFunctionArn(...))) does not add trigger to Lambda, where the Lambda is on another existing CF stack. The Rule has correct Lambda name in place and when I do edit+save on the Rule on AWS Console without changing anything, the trigger gets added to Lambda.

  2. We would like this Rule to be updated on every release to point a new Lambda (arn), so that in any time the Rule has only single target, but also the previous Lambda doesn't have the trigger in place anymore.

Reproduction Steps

  import { Function as LFunction } from "@aws-cdk/aws-lambda";

  public eventSubscription = new Rule(
    this,
    "MyEvent for my Lambda",
    {
      eventBus: EventBus.fromEventBusArn(
        this,
        "My EventBus",
        this.stack.getEnvrionmentVariable("eventBusArn")
      ),
      eventPattern: {
        detailType: [
          "myEvent",
        ],
      },
    }
  ).addTarget(
    new LambdaFunction(
      LFunction.fromFunctionArn(
        this,
        "myLambda",
        this.config.myLambdaArn
      )
    )
  );

What did you expect to happen?

Expected the Lambda to have the trigger in place and thus get the events from EventBridge as input events.

What actually happened?

Lambda didn't get any input trigger and didn't get any events either.

Environment

  • CLI Version : CDK 1.61.1 (?)
  • Framework Version: CDK 1.61.1
  • Node.js Version: NodeJS 12 (?)
  • OS : aws/codebuild/standard:3.0... TBD
  • Language (Version): Typescript (?)

Other

The Rule has correct Lambda name in place and when I do edit+save on the Rule on AWS Console without changing anything, the trigger gets added to Lambda.


This is 🐛 Bug Report

@dforsber dforsber added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Sep 24, 2020
@github-actions github-actions bot added the @aws-cdk/aws-events Related to CloudWatch Events label Sep 24, 2020
@marcioemiranda
Copy link

Hello,

I believe I am facing the same problem using CloudWatchEvents to trigger an existent function.

The problem is that the Lambda Resource Policy is not created.

If I run:
aws lambda get-policy --function-name MyFunction --region us-east-1

I get :

A client error (ResourceNotFoundException) occurred when calling the GetPolicy operation: The resource you requested does not exist.

So, if I run the following command to add a Lambda ResourcePolicy:

aws lambda add-permission \
--function-name MyFunction \
--statement-id MyId \
--action 'lambda:InvokeFunction' \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:123456789012:rule/MyRule

Then the trigger works as expected.

I have also tried to add the ResourcePolicy explicitly in the CDK app but it didn't work (should this be in a separate bug ticket?).

const lambdaFunction = Function.fromFunctionArn(this, "triggerFunction", "arn:aws:lambda:us-east-1:xxxxxxx:function:dummy");

        const onCommitRule = repo.onCommit('OnCommit', {
            ruleName: "myRule",
            target: new targets.LambdaFunction(lambdaFunction)
          });

The CDK code above won't create a ResourcePolicy in the lambda function.

lambdaFunction.addPermission("cloudWatchEvents", {
            principal: new ServicePrincipal('events.amazonaws.com'),
            sourceArn: onCommitRule.ruleArn
        });

The code above will not create a ResourcePolicy in the Lambda function as well.

Please advise if I should create a different ticket for adding a permission to an existent function.

PS: I have not tried setting a target to a Lambda function created in the same stack.

@marcioemiranda
Copy link

Quick update: The problem does not occur if the Lambda function is created in the same stack.

Adding the Lambda function as a target to the Rule will automatically create the Resource Policy and everything works as expected.

@dforsber
Copy link
Author

I added permission for the Lambda for events.amazonaws.com principal in the same stack where the Lambda is created. Then the Rule specified in another started working. However, Lambda AWS Console does not show any triggers as source, but the resource policy (permissions tab) still shows the permission. So, it works, but AWS Console is a bit inconsistent.

In general, I tend to like the fact that a stack can't modify resources in another stack. Not sure if this is by design or whether CF would need to have some additional permissions to be able to do cross stack changes while deploying the stack.

@leantorres73
Copy link

leantorres73 commented Sep 30, 2020

I'll try what you are suggesting @dforsber , because for me eventbridge is creating the rule, attaching the trigger but it's never being invoked which si weird.
I have the lambda and the rule in two different CDK Stacks
If I edit and save the rule it starts working, my impression was a policy issue and I can see here that's the problem, add target is not adding the permission.

I'll try this solution.
Thanks

@DaWyz
Copy link
Contributor

DaWyz commented Oct 3, 2020

The base-function construct implements the following:

  /**
   * Whether the addPermission() call adds any permissions
   *
   * True for new Lambdas, false for version $LATEST and imported Lambdas
   * from different accounts.
   */
  protected abstract readonly canCreatePermissions: boolean;

canCreatePermissions is automatically set to false when the stack doesn't match the stack of the Lambda function.

And canCreatePermission must be true for Function.addPermission to actually create the Lambda::Permission resource.

However, there is a solution to overcome that. You just need to do it the other way. Instead of calling the repository.onCommit in the stack where the repository is created, you want to do it on the Stack where the lambda function is created.

See example below:

#!/usr/bin/env node
import 'source-map-support/register';

import { App, Construct, Stack, StackProps } from '@aws-cdk/core';
import { IRepository, Repository } from '@aws-cdk/aws-codecommit';
import { LambdaFunction } from '@aws-cdk/aws-events-targets';
import { Code, Function, IFunction, Runtime } from '@aws-cdk/aws-lambda';

const app = new App();

interface LambdaStackProps extends StackProps {
  repositoryName: string;
}

class LambdaStack extends Stack {
  fn: IFunction;
  constructor(scope: Construct, id: string, props: LambdaStackProps) {
    super(scope, id, props);

    this.fn = new Function(this, 'lambda', {
      runtime: Runtime.NODEJS_12_X,
      code: Code.fromAsset('lambdas/oncommit'),
      handler: 'index.handler',
    });

    let repository = Repository.fromRepositoryName(this, 'repo', props.repositoryName);

    repository.onCommit('on-commit', {
      target: new LambdaFunction(this.fn),
    });
  }
}

class CodeCommitStack extends Stack {
  repository: IRepository;
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    this.repository = new Repository(this, 'my-test-repository', {
      repositoryName: 'my-test-repository',
    });
  }
}

let codecommit = new CodeCommitStack(app, 'codecommit-stack');

let lambdaStack = new LambdaStack(app, 'lambda-stack', {
  repositoryName: codecommit.repository.repositoryName,
});

Hope it helps !

@shivlaks shivlaks added p1 effort/medium Medium work item – several days of effort labels Dec 1, 2020
@SomayaB SomayaB removed the needs-triage This issue or PR still needs to be triaged. label Dec 7, 2020
@NGL321 NGL321 assigned rix0rrr and unassigned shivlaks Jan 25, 2021
@yogeshdass
Copy link

one workaround is like below use CfnPermission() instead of addpermission() :

        eventBus = _events.EventBus(self, "r1", event_bus_name="eb-bus")
        _ = _lambda.Function.from_function_arn(self, "lambda",function_arn=core.Fn.import_value("lambda-arn"))

        eventBusRule = _events.Rule(self, "r2", 
            enabled=True,
            event_bus=eventBus,
            event_pattern=_events.EventPattern(
                source="com.mycompany.event",
                detail_type="test-events"
            ),
            rule_name="eventbus-rule",
            targets=[
                _events_targets.LambdaFunction( _, event=_events.RuleTargetInput.from_event_path("$.detail"))
            ]
        )
        
        _lambda.CfnPermission(self, "lambdapermissionsforeventbus",
                              principal="events.amazonaws.com",
                              action="lambda:InvokeFunction",
                              source_arn=eventBusRule.rule_arn,
                              function_name=_.function_arn
        )

@mirkods
Copy link

mirkods commented Nov 12, 2021

Hi all,
I'm having the same problem, any updates?

@stephenwiebe
Copy link
Contributor

Just ran into this, the CfnPermission workaround that @yogeshdass suggested works for now.

@ShivamJoker
Copy link

Having the same issue, needs to manually add the trigger event.

@ShivamJoker
Copy link

ShivamJoker commented May 10, 2022

If you want it in TypeScript

    new CfnPermission(this, "lambda-permission-event-bus", {
      action: "lambda:InvokeFunction",
      sourceArn: mediaProcessUpdateRule.ruleArn,
      principal: "events.amazonaws.com",
      functionName: mediaProcessFn.functionArn,
    });

This worked after deleting and deploying stack again.

But AWS team you gotta fix this :(

@corymhall
Copy link
Contributor

This should work as long as you have either specified the account in the Stack environment or use fromFunctionAttributes() instead of fromFunctionArn. As long as it is able to determine whether the imported lamda exists in the same environment it should create the permission.

Does not work

new Stack(app, 'MyStack);
lambda.Function.fromFunctionArn()

Works

new Stack(app, 'MyStack', { env: { account: '11111111111', region: 'us-east-1' } });
lambda.Function.fromFunctionArn()

Or

new Stack(app, 'MyStack');
lambda.Function.fromFunctionAttributes({
  functionArn: '...',
  sameEnvironment: true,
});

@corymhall corymhall added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Aug 9, 2022
@github-actions
Copy link

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Aug 11, 2022
@ShivamJoker
Copy link

Give me few days I will try and update

@github-actions github-actions bot removed closing-soon This issue will automatically close in 4 days unless further comments are made. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Aug 12, 2022
@chotalia
Copy link

hi @corymhall I can confirm I am passing account and region but still when it is separate stack then trigger does not get created.

@otaviomacedo
Copy link
Contributor

@chotalia Did you try the fromFunctionAttributes suggestion by @corymhall? The sameEnvironment: true is the key to making this work.

Longer explanation: the framework only adds a Lambda permission (necessary for the link between rule and function to work from both sides) if they are in the same environment, which is set manually, or if they are in the same account. If you don't set sameEnvironment: true, it will try to check whether they are in the same account. But for that, it needs to parse the function ARN. Because the function ARN is a token, in this case, it considers that they are not in the same account, to be safe.

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-events Related to CloudWatch Events bug This issue is a bug. effort/medium Medium work item – several days of effort p1
Projects
None yet
Development

No branches or pull requests