Repository: serverless/serverless (JavaScript)
Date: 2020-03-17 00:50:45+00:00
Task type: Bug Fix

Issue:
Lambda Destinations: TypeError: Cannot read property 'Properties' of undefined
# Bug Report

## Description
SLS deploy throws error when using lambda destinations.

1. What did you do?
```
sls deploy --verbose --aws-s3-accelerate
```
1. What happened?
```
TypeError: Cannot read property 'Properties' of undefined
```
1. What should've happened? - should deploy successfully
1. What's the content of your `serverless.yml` file?
```
service: service

frameworkVersion: '>=1.28.0 <2.0.0'

provider:
  name: aws
  runtime: go1.x
  stage: production
  region: us-east-1
  memorySize: 128
  timeout: 10
  role: arn:aws:iam::123123:role/123-123-role
  environment: ${ssm:/aws/reference/secretsmanager/DDS~true}
  versionFunctions: false
  vpc: 
    securityGroupIds:
      - sg-123
    subnetIds:
      - subnet-123
      - subnet-123 

package:
  exclude:
    - ./**
  include:
    - ./bin/**

functions:
  consumer:
    reservedConcurrency: 3
    handler: bin/consumer
    destinations:
      onFailure: failure-notification
    events:
      - sqs:
          arn: arn:aws:sqs:us-east-1:12312312312
          batchSize: 10
```
1. What's the output you get when you use the `SLS_DEBUG=*` environment variable (e.g. `SLS_DEBUG=* serverless deploy`)
```
Serverless: Load command interactiveCli
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command config:tabcompletion
Serverless: Load command config:tabcompletion:install
Serverless: Load command config:tabcompletion:uninstall
Serverless: Load command create
Serverless: Load command install
Serverless: Load command package
Serverless: Load command deploy
Serverless: Load command deploy:function
Serverless: Load command deploy:list
Serverless: Load command deploy:list:functions
Serverless: Load command invoke
Serverless: Load command invoke:local
Serverless: Load command info
Serverless: Load command logs
Serverless: Load command metrics
Serverless: Load command print
Serverless: Load command remove
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command slstats
Serverless: Load command plugin
Serverless: Load command plugin
Serverless: Load command plugin:install
Serverless: Load command plugin
Serverless: Load command plugin:uninstall
Serverless: Load command plugin
Serverless: Load command plugin:list
Serverless: Load command plugin
Serverless: Load command plugin:search
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command upgrade
Serverless: Load command uninstall
Serverless: Load command login
Serverless: Load command logout
Serverless: Load command generate-event
Serverless: Load command test
Serverless: Load command dashboard
Serverless: Load command output
Serverless: Load command output:get
Serverless: Load command output:list
Serverless: Load command param
Serverless: Load command param:get
Serverless: Load command param:list
Serverless: [AWS ssm 200 1.328s 0 retries] getParameter({
  Name: '/aws/reference/secretsmanager/123',
  WithDecryption: true
})
Serverless: Invoke deploy
Serverless: Invoke package
Serverless: Invoke aws:common:validate
Serverless: Invoke aws:common:cleanupTempDir
Serverless: Packaging service...
Serverless: Excluding development dependencies...
 
  Type Error ---------------------------------------------
 
  TypeError: Cannot read property 'Properties' of undefined
      at AwsCompileFunctions.ensureTargetExecutionPermission (/usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:601:41)
      at AwsCompileFunctions.memoized [as ensureTargetExecutionPermission] (/usr/local/lib/node_modules/serverless/node_modules/lodash/lodash.js:10552:27)
      at AwsCompileFunctions.compileFunctionDestinations (/usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:579:12)
      at /usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:555:56
  From previous event:
      at /usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:555:40
  From previous event:
      at AwsCompileFunctions.compileFunction (/usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:121:25)
      at /usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:635:62
  From previous event:
      at AwsCompileFunctions.compileFunctions (/usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:635:22)
  From previous event:
      at Object.package:compileFunctions [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/aws/package/compile/functions/index.js:32:12)
      at /usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:55
  From previous event:
      at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:22)
      at PluginManager.spawn (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:510:17)
      at Deploy.<anonymous> (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:115:50)
  From previous event:
      at Object.before:deploy:deploy [as hook] (/usr/local/lib/node_modules/serverless/lib/plugins/deploy/deploy.js:100:30)
      at /usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:55
  From previous event:
      at PluginManager.invoke (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:490:22)
      at /usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:525:24
  From previous event:
      at PluginManager.run (/usr/local/lib/node_modules/serverless/lib/classes/PluginManager.js:525:8)
      at /usr/local/lib/node_modules/serverless/lib/Serverless.js:133:33
      at processImmediate (internal/timers.js:456:21)
      at process.topLevelDomainCallback (domain.js:137:15)
  From previous event:
      at Serverless.run (/usr/local/lib/node_modules/serverless/lib/Serverless.js:120:74)
      at /usr/local/lib/node_modules/serverless/bin/serverless.js:82:30
      at /usr/local/lib/node_modules/serverless/node_modules/graceful-fs/graceful-fs.js:136:16
      at /usr/local/lib/node_modules/serverless/node_modules/graceful-fs/graceful-fs.js:57:14
      at FSReqCallback.oncomplete (fs.js:154:23)
  From previous event:
      at /usr/local/lib/node_modules/serverless/bin/serverless.js:82:8
      at processImmediate (internal/timers.js:456:21)
      at process.topLevelDomainCallback (domain.js:137:15)
  From previous event:
      at Object.<anonymous> (/usr/local/lib/node_modules/serverless/bin/serverless.js:71:4)
      at Module._compile (internal/modules/cjs/loader.js:1151:30)
      at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)
      at Module.load (internal/modules/cjs/loader.js:1000:32)
      at Function.Module._load (internal/modules/cjs/loader.js:899:14)
      at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
      at internal/main/run_main_module.js:17:47
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com
 
  Your Environment Information ---------------------------
     Operating System:          darwin
     Node Version:              13.7.0
     Framework Version:         1.66.0
     Plugin Version:            3.5.0
     SDK Version:               2.3.0
     Components Version:        2.22.3
 
make: *** [deploy] Error 1
```


Issue discussion:
I tried standalone version, still the same issue.
I have the same bug and this is because you are specifying a 'role'. Remove the role, and you will be able to deploy.

From the stacktrace, if you check the file `serverless/lib/plugins/aws/package/compile/functions/index.js` at line 601, you will see this:
`const iamPolicyStatements = this.serverless.service.provider.compiledCloudFormationTemplate
      .Resources.IamRoleLambdaExecution.Properties.Policies[0].PolicyDocument.Statement;`

The thing is when you specify a role, then `IamRoleLambdaExecution` is null. That's why `IamRoleLambdaExecution.Properties` is failing with the error message `TypeError: Cannot read property 'Properties' of undefined`.
If you don't specify a role, then `IamRoleLambdaExecution` have some value and the code doesn't crash.

@aklein-dex i had the same resolution as well. I removed `role` and replaced it with `iamRoleStatements`. my functions need to run with certain roles.

thanks for input.

Solution patch:
diff --git a/lib/plugins/aws/package/compile/functions/index.js b/lib/plugins/aws/package/compile/functions/index.js
index 2ba23a8cff5..63ab5f46d96 100644
--- a/lib/plugins/aws/package/compile/functions/index.js
+++ b/lib/plugins/aws/package/compile/functions/index.js
@@ -575,8 +575,13 @@ class AwsCompileFunctions {
     };
     const destinationConfig = resource.Properties.DestinationConfig;
 
+    const hasAccessPoliciesHandledExternally = Boolean(
+      functionObject.role || this.serverless.service.provider.role
+    );
     if (destinations.onSuccess) {
-      this.ensureTargetExecutionPermission(destinations.onSuccess);
+      if (!hasAccessPoliciesHandledExternally) {
+        this.ensureTargetExecutionPermission(destinations.onSuccess);
+      }
       destinationConfig.OnSuccess = {
         Destination: destinations.onSuccess.startsWith('arn:')
           ? destinations.onSuccess
@@ -584,7 +589,9 @@ class AwsCompileFunctions {
       };
     }
     if (destinations.onFailure) {
-      this.ensureTargetExecutionPermission(destinations.onFailure);
+      if (!hasAccessPoliciesHandledExternally) {
+        this.ensureTargetExecutionPermission(destinations.onFailure);
+      }
       destinationConfig.OnFailure = {
         Destination: destinations.onFailure.startsWith('arn:')
           ? destinations.onFailure


Test patch:
diff --git a/lib/plugins/aws/package/compile/functions/index.test.js b/lib/plugins/aws/package/compile/functions/index.test.js
index 0c93b78470d..470d7dbc5f2 100644
--- a/lib/plugins/aws/package/compile/functions/index.test.js
+++ b/lib/plugins/aws/package/compile/functions/index.test.js
@@ -2622,9 +2622,9 @@ describe('AwsCompileFunctions', () => {
 });
 
 describe('AwsCompileFunctions #2', () => {
-  describe('Destinations', () => {
-    after(fixtures.cleanup);
+  after(fixtures.cleanup);
 
+  describe('Destinations', () => {
     it('Should reference function from same service as destination', () =>
       runServerless({
         cwd: fixtures.map.functionDestinations,
@@ -2691,5 +2691,29 @@ describe('AwsCompileFunctions #2', () => {
           })
         );
     });
+
+    it('Should respect `role` setting', () =>
+      fixtures
+        .extend('functionDestinations', { provider: { role: ' arn:aws:iam::XXXXXX:role/role' } })
+        .then(fixturePath =>
+          runServerless({
+            cwd: fixturePath,
+            cliArgs: ['package'],
+          }).then(serverless => {
+            const cfResources =
+              serverless.service.provider.compiledCloudFormationTemplate.Resources;
+            const naming = serverless.getProvider('aws').naming;
+            const destinationConfig =
+              cfResources[naming.getLambdaEventConfigLogicalId('trigger')].Properties
+                .DestinationConfig;
+
+            expect(destinationConfig).to.deep.equal({
+              OnSuccess: {
+                Destination: { 'Fn::GetAtt': [naming.getLambdaLogicalId('target'), 'Arn'] },
+              },
+            });
+            expect(destinationConfig).to.not.have.property('OnFailure');
+          })
+        ));
   });
 });