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

Bug Report : Not be able to use Fn::ImportValue or Ref in the Authorizer section of a File in *.YAML File #3129

Closed
KamroozN opened this issue Jan 23, 2017 · 15 comments
Labels

Comments

@KamroozN
Copy link

Not be able to use Fn::ImportValue or Ref in the Authorizer section of a File in *.YAML File

Description

Hi, It seems we found a bug. The scenario is as follows :

We defined a custom authorizer lambda function in a Cloudformation (stack A) and we exposed the ARN of the lambda function as an Output resource (Export name is "CustomAuthorizerDefaultFunction").
In the following Yml file which is located in a different Cloudformation stack (Stack B), we are going to Fn::ImportValue from cloudformation stack A. As we commented in the following Yaml file :
1- 'Fn::ImportValue': 'CustomAuthorizerDefaultFunction' works fine in the Resources-> Output section.
2- 'Fn::ImportValue': 'CustomAuthorizerDefaultFunction' does not work when we use it in Authorizer section of the function.
3- 'Fn::ImportValue': 'CustomAuthorizerDefaultFunction' works in the environment section of a function definition.
4- Also Besides 'Fn::ImportValue', Ref: AuthorizerArnImport does not work either.

Any thought ? If it is a known issue, any suggestions ?

Thanks

------------------------------------------------------ part of our Yml File----------------
service: usvc-dmp-rest
frameworkVersion: ">=1.0.0 <2.0.0"
plugins:

  • serverless-offline
    provider:
    profile: serverless-admin
    name: aws
    runtime: nodejs4.3
    memorySize: 128
    resources:
    Outputs:
    AuthorizerArnImport:
    Description: 'Authorizer Arn'
    Value:
    'Fn::ImportValue': 'CustomAuthorizerDefaultFunction'
    functions:
    myFunction:
    handler: 'app/endpoints/myFunction/handler.myFunctionHandler'
    environment:
    MY_THING:

Works

   'Fn::ImportValue': 'CustomAuthorizerDefaultFunction'
events:
  - http:
      path: aPath
      method: get
      authorizer:

Fails

arn:

Ref: AuthorizerArnImport

Works

arn: "arn:aws:lambda:us-east-1:xxxxxxx:function:CustomAuthorizer-DefaultFunction-1BT9PWQLLI7GI"

Fails?

        arn:
          'Fn::ImportValue': 'CustomAuthorizerDefaultFunction'
      integration: lambda
      request:
        template:
          application/json: ${self:custom.requestTemplate}
      cors: ${self:custom.cors}		
  • Serverless Framework Version you're using:

  • Stack Trace:

TypeError: functionArn.split is not a function
at Object.extractAuthorizerNameFromArn (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\lib\naming.js:110:34)
at AwsCompileApigEvents.getAuthorizer (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\deploy\compile\events\apiGateway\lib\validate.js:204:37)
at _.forEach (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\deploy\compile\events\apiGateway\lib\validate.js:50:36)
at arrayEach (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:537:11)
at Function.forEach (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:9344:14)
at _.forEach (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\deploy\compile\events\apiGateway\lib\validate.js:42:9)
at C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:4970:15
at baseForOwn (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:3020:24)
at C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:4939:18
at Function.forEach (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\lodash\lodash.js:9344:14)
at AwsCompileApigEvents.validate (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\deploy\compile\events\apiGateway\lib\validate.js:41:7)
at deploy:compileEvents (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\plugins\aws\deploy\compile\events\apiGateway\index.js:42:31)
at BbPromise.reduce (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\lib\classes\PluginManager.js:160:50)
at tryCatcher (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\util.js:16:23)
at Object.gotValue (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\reduce.js:157:18)
at Object.gotAccum (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\reduce.js:144:25)
at Object.tryCatcher (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:510:31)
at Promise._settlePromise (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:567:18)
at Promise._settlePromise0 (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:612:10)
at Promise._settlePromises (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\promise.js:691:18)
at Async._drainQueue (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:138:16)
at Async._drainQueues (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:148:10)
at Immediate.Async.drainQueues (C:\Users\KamroozN\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:17:14)
at runCallback (timers.js:649:20)
at tryOnImmediate (timers.js:622:5)
at processImmediate [as _immediateCallback] (timers.js:594:5)

Your Environment Information -----------------------------
OS: win32
Node Version: 6.9.3
Serverless Version: 1.5.0

@pmuens pmuens added the bug label Jan 23, 2017
@tgjorgoski
Copy link

tgjorgoski commented Jan 29, 2017

Seems that the problem in principle stems from using "arn" field for both pointing to a function for custom authorizer, and to point to a cognito user pool.
There is an IF sentence in /Users/ssdessign/work/forks/serverless/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js , line 1204 which tries to figure out which of those two is the case, however this logic fails in the case when there is an Fn::ImportValue.
Probably the user will have to explicitly state if they want to use a custom authorizer or cognito user pool authorizer.
Maybe differentiating by using poolArn: in this case instead of arn: ?

@tgjorgoski
Copy link

tgjorgoski commented Jan 30, 2017

I tried the above approach and it works. That is - I changed the code to use poolarn for Cognito User Pool default authorizer, and left arn just for the case of the custom authorizer. After that I tested with Fn::ImportValue, and it works fine.

However, I think there needs to be a discussion about how to do this, as there are multiple options. Couple that I can think of:

  1. In addition to poolarn, leave the special logic for arn, so that in specific cases also covers Cognito User Pool as it does now (BTW the logic is - arn is a string and can be recognized as Cognito User Pool arn using regex).
    That way Serverless stays backward compatible. Things get little messy in the code, and harder to explain/document, however maybe just the poolarn is documented as a way to use Cognito User Pools.
  2. Remove the special logic. Use arn if you want custom authorizer. Use poolarn if you want to use default Cognito User Pool authorizer. Clean code, but breaking change.
  3. Continue using just the arn parameter ( no poolarn), but add defaultauthorizer boolean parameter, which if true means that serverless should treat the arn parameter as pointing to a Cognito User Pool.

tgjorgoski pushed a commit to tgjorgoski/serverless that referenced this issue Feb 4, 2017
adds poolarn parameter to the authorizer section for api gateway. to be used when specifying 'arn' parameter is not sufficient for determining if the reference is an authorizer function or cognito user pool.
Specifically that is the case when Fn:ImportValue is used.
tgjorgoski pushed a commit to tgjorgoski/serverless that referenced this issue Feb 12, 2017
* fix-for-serverless#3129:
  use poolarn , instead of arn for the cognito user pool
@eahefnawy
Copy link
Member

Closing...please check the comment in the PR for explanation

@ProTip
Copy link

ProTip commented Mar 2, 2017

Can we open this again? It's impacting me right now and I don't feel there is proper resolution.

IMHO the schema under authorizer is overloaded, and the backing code brittle. I believe that:

  • Any property that ought to support CloudFormation replacement should; otherwise risk frustrating users when they run into surprises
  • This overloads schema for two quite different authorizers(cognito user pool and custom)
  • This unnecessarily couples the customer authorizer to a particular project/repo
  • The error message functionArn.split is not a function is a poor message for a known issue

@pmuens
Copy link
Contributor

pmuens commented Mar 3, 2017

@ProTip thanks for reaching out. 👍

Were you able to solve this problem somehow? If so, how did you do it? Or are you striving for an easier way to configure it?

@ProTip
Copy link

ProTip commented May 15, 2017

I worked around this by encoding information into the naming schema.

However, I believe that the configuration should be more consistent. "Ref" and "Fn::GetAtt" are the idiomatic way to link resources together with AWS CloudFormation; this should be supported throughout the config IMHO. Otherwise there are surprises; like again today with the SNS topic arn not able to be Ref'd.

@pmuens
Copy link
Contributor

pmuens commented May 18, 2017

Thanks for getting back @ProTip 👍

Yes, we're thinking about a global arn parser (see #3212) so that this can be re-used throughout the codebase in a reliable way.

@aymericaitamer
Copy link

Hi guys,

I worked around this by using cloud formation output in environment variable.

authorizer:
  arn: ${self:provider.environment.USERPOOL_ARN}

Then in your environment variables :

environment:
    STACK_NAME: ${self:service}-${opt:stage, self:provider.stage}
    USERPOOL_ARN: ${cf:${self:provider.environment.STACK_NAME}.UserPoolArn}

And in your cloud formation outputs :

Outputs:
  UserPoolArn:
    Value:
      'Fn::GetAtt': [ UserPool, Arn ]

@cjo2
Copy link

cjo2 commented Feb 25, 2018

@aymericaitamer I attempted to use this solution, but I had to let the UserPool be created first. After the first deployment, I could add the authorizer and environment variables. Was that the intended function of your solution?

Thanks!

@sergiobellon
Copy link

I am having the same issue/

The following environment parameter of a function :

BATCH_JOB_QUEUE:
   'Fn::ImportValue': 'BatchJobQueue-${self:provider.stage}'

Passes to the function as:
BATCH_JOB_QUEUE: {"Fn::ImportValue":"BatchJobQueue-dev"}

@stelone
Copy link

stelone commented Nov 16, 2018

I have the same issue with set authorizer arn.
I use something like:

USERPOOL_ARN: ${cf:${self:provider.environment.STACK_NAME}.UserPoolArn}

that actualy work... not super but it's working...

that not work for me :

BATCH_JOB_QUEUE: {"Fn::ImportValue":"BatchJobQueue-dev"}

@andreanaya
Copy link

This worked for me, basically you need to name the authorizer to make it work

hello-world:
  handler: hello-world.handler
  events:
    - http:
        path: /hello-world
        authorizer:
          name: SharedAuthorizer
          arn:
            'Fn::ImportValue': ${self:provider.stage}-SharedAuthorizer

@kaitlynbrown
Copy link

When I try the above syntax, I get this error on the first line of the next function that is defined in the template:
bad indentation of a mapping entry

@librarywebchic
Copy link

I tried adding a name as well and it doesn't work. I get the functionArn.split is not a function error

@tobinbc
Copy link

tobinbc commented Oct 28, 2022

This still is an issue but specifying it like this seems to solve it

locationomatic:
  handler: lambda/locationomatic/index.handler
  events:
    - http:
        method: POST
        path: locationomatic
        cors: true
        authorizer:
          name: Cognito
          type: COGNITO_USER_POOLS
          arn: !GetAtt CognitoUserPoolUserPool.Arn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet