serverless-application-model icon indicating copy to clipboard operation
serverless-application-model copied to clipboard

ApiKeyRequired flag set to true does not result in API key being required on API Gateway

Open nullpointer800 opened this issue 5 years ago • 3 comments

Description:

Upon configuring SAM .yaml template for a simple Lambda functiion, with ApiKeyRequired flag set to true for the Auth under AWS::Serverless::Api, the resulting API Gateway that is created after deployment does not require an API key.

Steps to reproduce the issue:

  1. Configure the .yaml with ApiKeyRequired set to true.
  2. Build and deploy the function, using the following commands: sam build sam deploy --guided
  3. View the gateway in the AWS console.

Observed result: The gateway does not require an API key.

Expected result: The gateway requires an API key.


Sample configurations file attached. One is very straightforward - it should work. The other is what I had after trying to create everything explicitly - still no dice. template.txt template2.txt


The same outcome (no API key required) is also achieved by setting ApiKeyRequired to true underneath an ApiFunctionAuth within an Api EventSource, indicating some similar bug.

nullpointer800 avatar Apr 08 '20 06:04 nullpointer800

In fact, I observe the following unexpected(?) behavior: if ApiKeyRequired attribute exists and is set to the result of the expression then it is always 'true' no matter what the result of the expression is:

ValidationApi:
    Type: 'AWS::Serverless::Api'
    Properties:
        Auth:
            ApiKeyRequired: 
                !If [UseApiKey, 'true', 'false']

And yes, I checked 10x that the condition UseApiKey behaves as expected

paul-michalik avatar Sep 05 '20 12:09 paul-michalik

I'm just experiencing the scenario exposed by @paul-michalik . I'm using a function to parameterize the ApiKey requirement when I deploy my stack using a CI. No matter what the comparator or function gives, as a result, the value of ApiKeyRequired is always true.

An ugly workaround is to set a default value for a parameter like.UseApiKey to an empty string '' and set the ApiKeyRequired to !Ref UseApiKey

So, if I pass UseApiKey with any value (which includes false or wololo), it will be transformed to true, but if I don't pass that parameter, it will be set to the default empty string, and it will be transformed to false.

rcarrillodev avatar Aug 19 '21 20:08 rcarrillodev

Facing the same issue, would like to enable ApiKeyRequired for the Api Gateway generically without having to enable it for each individual function but it is not applying. Any updates on this?

A workaround for now is to just enable it at function level but its not really ideal.

omardoma avatar Nov 25 '21 16:11 omardoma

Any update on the issue experienced by @rcarrillodev ? I just had the same problem as well, and their workaround saved my day.

Oddly enough, it seems an empty parameter is really required. I've tried the following statement:

ApiKeyRequired: !If [IsUsingAPIKey, true, '']

With IsUsingAPIKey being a condition based on UseAPIKey parameter.

It didn't work. I really had to set UseAPIKey parameter to '' and then wrote the following statement:

ApiKeyRequired: !Ref UseAPIKey

guillaume-gc avatar Nov 22 '22 09:11 guillaume-gc

Hey @nullpointer800, I deployed your sample template but wasn't able to reproduce the issue. As you can see from the screenshot of the AWS Console, the API Key is required when I deploy your template.txt. Can you check if the issue still persists on your end?

Screen Shot 2022-11-22 at 10 27 23 AM

aaythapa avatar Nov 22 '22 18:11 aaythapa

TL;DR: Add AWS::LanguageExtensions to the Transform section. See https://github.com/aws/serverless-application-model/issues/2533.

Tried reproducing with:

Transform: AWS::Serverless-2016-10-31
Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        ApiKeyRequired: true
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      InlineCode: foo
      Handler: bar
      Runtime: python3.8
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId: !Ref MyApi

Deploy with:

sam deploy --region us-west-2 --resolve-s3 --capabilities CAPABILITY_IAM --stack-name test-1553 --template template.yaml

API key is required, as expected.

So then I try with an intrinsic functions, similar to what @guillaume-gc and @rcarrillodev describe:

Transform: AWS::Serverless-2016-10-31
Parameters:
  Foo:
    Default: "false"
    Type: String
Conditions:
  UseApiKey:
    Fn::Equals:
      - !Ref Foo
      - "true"
Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        ApiKeyRequired: !If [UseApiKey, true, false]
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      InlineCode: foo
      Handler: bar
      Runtime: python3.8
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId: !Ref MyApi

It still shows API key is required, although Foo is "false".

The suspicious behavior seems to come from here:

https://github.com/aws/serverless-application-model/blob/56d34ff9761da6a64cc4f7424f1fb46919c5b3e6/samtranslator/model/eventsources/push.py#L795-L807

Basically, as long as ApiKeyRequired is truthy, it'll follow the logic to require the API key. And since the SAM transform receives the template as-is (including the intrinsic function), if it doesn't to resolve the intrinsic !If it'll still be considered truthy (!If shows up as a non-empty object in the SAM transform input).

So it looks like an issue with unresolved intrinsic being evaluated as truthy. To fix this, we can add AWS::LanguageExtensions to the Transform section, as it resolves any intrinsic functions known before deployment:

Transform:
  - AWS::LanguageExtensions
  - AWS::Serverless-2016-10-31
Parameters:
  Foo:
    Default: "false"
    Type: String
Conditions:
  UseApiKey:
    Fn::Equals:
      - !Ref Foo
      - "true"
Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        ApiKeyRequired: !If [UseApiKey, true, false]
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      InlineCode: foo
      Handler: bar
      Runtime: python3.8
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get
            RestApiId: !Ref MyApi

And this deploys with API key disabled, as expected. See https://github.com/aws/serverless-application-model/issues/2533 for more information.

hoffa avatar Dec 06 '22 01:12 hoffa

Adding AWS::LanguageExtensions will cause the other parameter parsing failure.

For example:

Parameters:
...
  LambdaMemorySize:
    Description: Default lambda function size
    Type: Number
    Default: 128
...
Resources
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Runtime: python3.9
      MemorySize: !Ref LambdaMemorySize

The code above will report an invalid type for MemorySize

hf-qin avatar Feb 24 '23 01:02 hf-qin

@hf-qin Right, AWS::LangagueExtensions resolves it as a string, which CloudFormation accepts but SAM doesn't. We've fixed it in https://github.com/aws/serverless-application-model/pull/2928 and will roll out over the coming weeks.

hoffa avatar Feb 24 '23 01:02 hoffa