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

Function specific ApiKeyRequired Auth property does not override the global API default #1514

Open
piyushjaware opened this issue Mar 12, 2020 · 6 comments
Labels
area/resource/api maintainer/need-followup stage/needs-feedback Needs feedback from the community (are you also interested in/experiencing this?) type/feature

Comments

@piyushjaware
Copy link

piyushjaware commented Mar 12, 2020

The documentation states that if you have specified ApiKeyRequired: true globally on the API and want to make a specific Function public, you can override it with the following in the Function's event source:

  ApiKeyRequired: false

However, this does not seem to function as stated.

Steps to reproduce the issue:
Here's the template I used.

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

Globals:
  Function:
    Timeout: 3
    Runtime: nodejs12.x

Resources:
  MyAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: MyAPI
      StageName: Default
      EndpointConfiguration: REGIONAL
      Auth:
        ApiKeyRequired: true
      DefinitionBody:
        openapi: 3.0.0
        x-amazon-apigateway-api-key-source: "HEADER"
        paths:
          /public:
            get:
              x-amazon-apigateway-integration:
                type: aws_proxy
                httpMethod: POST
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PublicFunction.Arn}/invocations
          /private:
            get:
              x-amazon-apigateway-integration:
                type: aws_proxy
                httpMethod: POST
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PrivateFunction.Arn}/invocations

  PublicFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: PublicFunction
      Role: !GetAtt LambdaRole.Arn
      Handler: src/public.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /public
            Method: ANY
            RestApiId:
              Ref: MyAPI
            Auth:
              ApiKeyRequired: false

  PrivateFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: PrivateFunction
      Role: !GetAtt LambdaRole.Arn
      Handler: src/private.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /private
            Method: ANY
            RestApiId:
              Ref: MyAPI

  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  
  ApiKey:
    Type: AWS::ApiGateway::ApiKey
    Properties:
      Name: !Join [ "-", [ MyAPI, "ApiKey" ]]
      Description: "APIkey"
      Enabled: true
      GenerateDistinctId: false 

  ApiUsagePlan:
    Type: AWS::ApiGateway::UsagePlan
    DependsOn: MyAPIDefaultStage
    Properties:
      ApiStages:
        - ApiId: !Ref MyAPI
          Stage: Default
      Description: !Join [ "-", [ MyAPI, "UsagePlan" ] ]
      UsagePlanName: !Join [ "-", [ MyAPI, "UsagePlan" ] ]

  ApiUsagePlanKey:
    Type: AWS::ApiGateway::UsagePlanKey
    Properties:
      KeyId: !Ref ApiKey
      KeyType: API_KEY
      UsagePlanId: !Ref ApiUsagePlan

Outputs:

  APi:
    Description: "API Gateway endpoint URL"
    Value: !Sub "https://${MyAPI}.execute-api.${AWS::Region}.amazonaws.com/Default/public"

Observed result:
API Key Still required

Expected result:
The /public route should have API Key Required = False.

@gaurang171
Copy link

I am having the same issue. did you find a solution?
the only other solution I am seeing is having auth at method level and security
and use of securityDefinitions for definationBody instead of global Auth

@piyushjaware
Copy link
Author

piyushjaware commented Jun 2, 2020

@gaurang171 I went with the swagger route for now.
Note: Here's the detailed solution if you are interested.

@sriram-mv sriram-mv added the stage/bug-repro The issue/bug needs to be reproduced label Feb 22, 2021
@qingchm
Copy link
Contributor

qingchm commented Mar 3, 2021

Hi, @piyushjaware I can confirm that I was able to reproduce this, after deployment the API gateway does show "API Key Required" for the public GET, will investigate on the cause. Thanks for reporting this!

@qingchm qingchm added stage/needs-investigation Requires a deeper investigation and removed stage/bug-repro The issue/bug needs to be reproduced labels Mar 5, 2021
@qingchm
Copy link
Contributor

qingchm commented Mar 5, 2021

Hey @piyushjaware and @gaurang171 here's what is going on:
SAM do support overriding Function specific ApiKeyRequired Auth property over the global API default, but this only happens when you do not have an explicit definition for the API's definition body. When you do not have a definition body provided, SAM will generate it for you, which will support the overriding that you want. But we do not touch the settings that customers define in their template's API definition so far. So a template like this actually achieves what you want:

Resources:
  MyAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: MyAPI
      StageName: Default
      EndpointConfiguration: REGIONAL
      Auth:
        ApiKeyRequired: true

  PublicFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: PublicFunction
      Role: !GetAtt LambdaRole.Arn
      InlineCode: "code"
      Handler: index.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /public
            Method: get
            RestApiId:
              Ref: MyAPI
            Auth:
              ApiKeyRequired: false

  PrivateFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: PrivateFunction
      Role: !GetAtt LambdaRole.Arn
      InlineCode: "code"
      Handler: index.handler
      Events:
        API:
          Type: Api
          Properties:
            Path: /private
            Method: get
            RestApiId:
              Ref: MyAPI

I have verified that deployments with this actually works with ApiGateway's ApiKeyRequired field correctly set up. Currently SAM does not support overriding if you have a definition body defined. Let me know if you want SAM to override over your own defined definition body, I will view this as a feature request. Right now the workaround would be to not input your definition body and let SAM do it for you. If this does not satisfy your need, I would recommend after the translation use the translated template to modify the swagger yourself (just change

                "security": [
                  {
                    "api_key": []
                  }
                ],  

to

                "security": [],

I hope this helps!

@qingchm qingchm added area/resource/api stage/needs-feedback Needs feedback from the community (are you also interested in/experiencing this?) type/feature and removed stage/needs-investigation Requires a deeper investigation labels Mar 5, 2021
@mrsan22
Copy link

mrsan22 commented Jun 6, 2022

@qingchm Your answer helped me in the scenario where I wanted API Key required for HTTP (GET, POST) methods except OPTIONS (for CORS support.)

@bogartlisa
Copy link

I have been struggling with this issue for a couple days now. It seems that no matter how I try to set the api key config - either in the definition body or via the sam template, I cannot get the appropriate settings to deploy. I have tried removing the API Key config from my template and only setting in the definition doc:

x-amazon-apigateway-api-key-source: "HEADER"
paths:
:
security:
- api_key: []
- AccountApiAuthorizerFunction: []

securitySchemes:
api_key:
type: apiKey
name: x-api-key
in: header
x-amazon-apigateway-api-key-source : HEADER

I have tried only setting the API key via the template:
MyApi:
Name: MyApi
Type: AWS::Serverless::Api
Properties:
:
Auth:
ApiKeyRequired: false # turns off API Key for all methods
Authorizers:
:
ResourcePolicy:
:

MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: lambdas/src/handlers/junk/
Handler: handler.lambdaHandler
Events:
MyFunctionEvent:
Type: Api
Properties:
Path: /mypath
Method: put
RestApiId: !Ref MyApi
Auth:
ApiKeyRequired: true # overrides and turns on API Key for just this method

I have tried various combinations of the above and so far no magic. It seems whatever I set as the value for the API trumps any further configuration. I have also tried not setting the ApiKeyRequired at all for the API and that doesn't work either.

I can manually adjust the configuration in the console and get things working the way I want but I cannot for the life of me get the sam deploy to deploy that configuration. I have even tried creating the configuration that I want, exporting the definition and then deploying that. Still doesn't work. Really don't want to build 2 separate APIs just because I can't get the deployment to work as intended.

What am I doing wrong??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/resource/api maintainer/need-followup stage/needs-feedback Needs feedback from the community (are you also interested in/experiencing this?) type/feature
Projects
None yet
Development

No branches or pull requests

7 participants