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

Unable to set authorizer on AWS::Serverless::HttpApi on $default path #2481

Open
rockey5520 opened this issue Jan 9, 2021 · 18 comments
Open

Comments

@rockey5520
Copy link

rockey5520 commented Jan 9, 2021

Description:

Unable to set OAuth2 authorizer on API method [x-amazon-apigateway-any-method] for path [$default]

Steps to reproduce:

Below is template.Yaml file used and when run sam deploy gives errror as

Waiting for changeset to be created..
"Error: Failed to create changeset for the stack: finapi, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [XXX] is invalid. Event with id [HttpApiEvent] is invalid. Unable to set Authorizer [MyOauth2Authorizer] on API method [x-amazon-apigateway-any-method] for path [$default] because the related API does not define any Authorizers."

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
  StageName:
    Type: String
    Default: Prod
Description: XXX

Globals:
  Api:
    EndpointConfiguration: REGIONAL
  Function:
    Timeout: 180


Resources:
  Api:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Ref StageName
      Auth:
        Authorizers:
          MyOauth2Authorizer:
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              audience:
                - https://aws-api-gateway
              issuer: "https://xxxx.eu.auth0.com/"
        DefaultAuthorizer: MyOauth2Authorizer

  FinApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: com.StreamLambdaHandler::handleRequest
      Runtime: java11
      CodeUri: api
      MemorySize: 2048
      Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
        Variables:
          PARAM1: VALUE
      Events:
        HttpApiEvent:
          Type: HttpApi
          Properties:
            TimeoutInMillis: 20000
            PayloadFormatVersion: '2.0'
            Auth:
              Authorizer: MyOauth2Authorizer

Outputs:
  FApiFunctionApi:
    Description: URL for application
    Value: !Sub 'https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/pets'
    Export:
      Name: FApiFunctionApi

Observed result:

Waiting for changeset to be created..
Error: Failed to create changeset for the stack: finapi, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FinApiFunction] is invalid. Event with id [HttpApiEvent] is invalid. Unable to set Authorizer [MyOauth2Authorizer] on API method [x-amazon-apigateway-any-method] for path [$default] because the related API does not define any Authorizers.

Expected result:

function with API method [x-amazon-apigateway-any-method] for path [$default] is created on API gateway with OAuth 2.0/JWT authorizer configured

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS: Ubuntu
  2. sam --version: 1.15.0

Add --debug flag to command you are running

@spirulence
Copy link

Hey, I think you're encountering this issue because you're missing the ApiId property on HttpApiEvent, not because of an issue with the SAM CLI. I haven't tried your stack myself because the meaningful indentation has been stripped from your YAML

@hoffa hoffa added the stage/needs-investigation Requires a deeper investigation label Jan 18, 2021
@aahung
Copy link
Contributor

aahung commented Jan 19, 2021

(*I made an edit to make yaml formatted.)

Assuming I understand correctly, what you are trying to do here is quite similar to one of our example "HttpApi with configuration settings" and you can find it here: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-httpapi.html, let me paste it at the end of this comment. Both are trying to "define a AWS::Serverless::HttpApi and use it in a function."

You can try to replace

...
        HttpApiEvent:
          Type: HttpApi
          Properties:
            TimeoutInMillis: 20000
            PayloadFormatVersion: '2.0'
            Auth:
              Authorizer: MyOauth2Authorizer
...

with this

...
        HttpApiEvent:
          Type: HttpApi
          Properties:
            ApiId: !Ref Api
            TimeoutInMillis: 20000
            PayloadFormatVersion: '2.0'

About ApiId

ApiId
Identifier of an AWS::Serverless::HttpApi resource defined in this template.
If not defined, a default AWS::Serverless::HttpApi resource is created called ServerlessHttpApi using a generated OpenApi document containing a union of all paths and methods defined by Api events defined in this template that do not specify an ApiId.
This cannot reference an AWS::Serverless::HttpApi resource defined in another template.
Type: String
Required: No
AWS CloudFormation compatibility: This property is unique to AWS SAM and doesn't have an AWS CloudFormation equivalent.
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-httpapi.html

(Example) HttpApi with configuration settings

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
  StageName:
    Type: String
    Default: Prod
    
Resources:
  HttpApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      InlineCode: |
          def handler(event, context):
              import json
              return {
                  "statusCode": 200,
                  "body": json.dumps(event),
              }
      Handler: index.handler
      Runtime: python3.7
      Events:
        ExplicitApi: # warning: creates a public endpoint
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Method: GET
            Path: /path
            TimeoutInMillis: 15000
            PayloadFormatVersion: "2.0"
            RouteSettings:
              ThrottlingBurstLimit: 600

  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Ref StageName
      Tags:
        Tag: Value
      AccessLogSettings:
        DestinationArn: !GetAtt AccessLogs.Arn
        Format: $context.requestId
      DefaultRouteSettings:
        ThrottlingBurstLimit: 200
      RouteSettings:
        "GET /path":
          ThrottlingBurstLimit: 500 # overridden in HttpApi Event
      StageVariables:
        StageVar: Value
      FailOnWarnings: True

  AccessLogs:
    Type: AWS::Logs::LogGroup

Outputs:
  HttpApiUrl:
    Description: URL of your API endpoint
    Value:
      Fn::Sub: 'https://${HttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${StageName}/'
  HttpApiId:
    Description: Api id of HttpApi
    Value:
      Ref: HttpApi

@aahung aahung removed the stage/needs-investigation Requires a deeper investigation label Jan 19, 2021
@rockey5520
Copy link
Author

rockey5520 commented Jan 19, 2021

Hi @aahung ,

I found changing the template to the below structure worked. Is this the right way to construct it?

https://gist.github.com/rockey5520/a654124bb6b891ce329470f1c0d63474

@aahung
Copy link
Contributor

aahung commented Jan 19, 2021

Hi @aahung ,

I found changing the template to the below structure worked. Is this the right way to construct it?

https://gist.github.com/rockey5520/a654124bb6b891ce329470f1c0d63474

+ Add APIStage                                  AWS::ApiGatewayV2::Stage 
+ Add API                                       AWS::ApiGatewayV2::Api 
+ Add ServerlessHttpApiApiGatewayDefaultStage   AWS::ApiGatewayV2::Stage 
+ Add ServerlessHttpApi                         AWS::ApiGatewayV2::Api 
+ Add XFunctionHttpApiEventPermission           AWS::Lambda::Permission 
+ Add XFunctionRole                             AWS::IAM::Role 
+ Add XFunction                                 AWS::Lambda::Function 

Your template creates two APIs, I don't think it is what you want.

Would you mind trying to write your template based on the example I sent you? Like this:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
  StageName:
    Type: String
    Default: Prod
    
Resources:
  HttpApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      InlineCode: |
          def handler(event, context):
              import json
              return {
                  "statusCode": 200,
                  "body": json.dumps(event),
              }
      Handler: index.handler
      Runtime: python3.7
      Events:
        ExplicitApi: # warning: creates a public endpoint
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Method: GET
            Path: /path
            TimeoutInMillis: 15000
            PayloadFormatVersion: "2.0"
            RouteSettings:
              ThrottlingBurstLimit: 600

  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Ref StageName
      Tags:
        Tag: Value
      AccessLogSettings:
        DestinationArn: !GetAtt AccessLogs.Arn
        Format: $context.requestId
      DefaultRouteSettings:
        ThrottlingBurstLimit: 200
      RouteSettings:
        "GET /path":
          ThrottlingBurstLimit: 500 # overridden in HttpApi Event
      StageVariables:
        StageVar: Value
      FailOnWarnings: True
+      Auth:
+        Authorizers:
+          MyOauthAuthorizer:
+            IdentitySource: $request.header.Authorization
+            JwtConfiguration:
+              audience:
+                - https://awsgateway
+              issuer: "https://xxx.xx.com/"
+        DefaultAuthorizer: MyOauthAuthorizer

  AccessLogs:
    Type: AWS::Logs::LogGroup

Outputs:
  HttpApiUrl:
    Description: URL of your API endpoint
    Value:
      Fn::Sub: 'https://${HttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${StageName}/'
  HttpApiId:
    Description: Api id of HttpApi
    Value:
      Ref: HttpApi

@rockey5520
Copy link
Author

Hi @aahung

I tried with the structure given above. But I need to make a small change where my API Gateway needs to accept any HTTP methods and pass the request to lambda and replaced the above structure PATH to be as / and removed METHOD. By doing so I am getting error as

CREATE_FAILED AWS::ApiGatewayV2::Api HttpApi Warnings found during import: Parse
issue: attribute paths. Resource $default
should start with / (Service:
AmazonApiGatewayV2; Status Code: 400; Error
Code: BadRequestException; Request ID:
a60fsasa9a83-a9433g34gh6d-43c7-b1b0-4aa65ab65836; Proxy:
null) (Service: null; Status Code: 404; Error
Code: BadRequestException; Request ID: null;
Proxy: null)
ROLLBACK_IN_PROGRESS AWS::CloudFormation::Stack finapi The following resource(s) failed to create:
[HttpApi]. Rollback requested by user.

@aahung
Copy link
Contributor

aahung commented Jan 25, 2021

Can you post your updated template here?

@rockey5520
Copy link
Author

Sure @aahung ,

I am trying to get HttpAPI on gateway with $default route which can accept ANY HTTP method
image

Template.yaml I tried using is : https://gist.github.com/rockey5520/8d9ae3828075149b40a31c6acad68476

@c2tarun
Copy link
Contributor

c2tarun commented Jan 27, 2021

Sorry for the delay @rockey5520. Support for $default route was added at a later date as part of a quick create for HttpApi. SAM do not have support for this yet. When you declare Path as $default SAM puts it in Path body which based on OpenAPI specification need to start with a /, that is why you are seeing that error.

I am marking this issue as a feature request and will update after discussing in team.

Please let me know if you have any questions.

Thanks
Tarun

@rockey5520
Copy link
Author

rockey5520 commented Jan 29, 2021

Thank @c2tarun for answering. One question i have is,

via SAM template is it possible to create a method OPTIONS to the httpapi gateway which does not need to integrate with lambda but it does need to exist for my case?

Reason :
Use case I have is to build an httpapi integrated to one lambda via /{path+}(GET, POST, PATCH, DELETE) and direct all calls to lambda and I have accomplished this with SAM, and works well when I invoke the endpoint via curl/postman but facing CORS issue when calling the same endpoint via frontend due to the reason there is no OPTIONS method defined on httpapi.

I was able to overcome this situation by setting OPTIONS on httpapi via console but it would nice to have that in template.

Hope my question makes sense or let me know I will try to rephrase.

The same was accomplished via restapi following https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html but I am looking for the same in httpapi

@pratikpc
Copy link

pratikpc commented Jan 30, 2021

@ghost
Copy link

ghost commented Apr 20, 2021

I have the same issue with Sam local and HttpApi auth... it works fine when deployed but the Auth is not used locally... Any ideas ?

@aahung
Copy link
Contributor

aahung commented Apr 20, 2021

As for auth support in sam local, it is not yet supported in AWS SAM CLI. Please refer to the issue aws/aws-sam-cli#137

@aahung
Copy link
Contributor

aahung commented Apr 20, 2021

Thank @c2tarun for answering. One question i have is,

via SAM template is it possible to create a method OPTIONS to the httpapi gateway which does not need to integrate with lambda but it does need to exist for my case?

Reason :
Use case I have is to build an httpapi integrated to one lambda via /{path+}(GET, POST, PATCH, DELETE) and direct all calls to lambda and I have accomplished this with SAM, and works well when I invoke the endpoint via curl/postman but facing CORS issue when calling the same endpoint via frontend due to the reason there is no OPTIONS method defined on httpapi.

I was able to overcome this situation by setting OPTIONS on httpapi via console but it would nice to have that in template.

Hope my question makes sense or let me know I will try to rephrase.

The same was accomplished via restapi following https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html but I am looking for the same in httpapi

HttpApi has CorsConfiguration to enable CORS (in my experience, with this property set, there is still no OPTIONS defined in httpapi but CORS works). https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-httpapi.html#sam-httpapi-corsconfiguration

@tbenhamou
Copy link

Hey guys,

The same issue is driving me crazy for the last 2 days, I hope someone here can help me.
Here is the error I can see in my Lambda function:
image
I indeed can't see the route in the API Gateway console.

Here is my template:

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Cognito to API Gateway HTTP API (JWT)

Parameters:
  Environment:
    Description: Environment to deploy to.
    Type: String
    AllowedValues:
      - dev
      - prd

Globals:
  Function:
    Runtime: python3.9
    MemorySize: 128
    Timeout: 5
    Description: "aws:states:opt-in"
    ReservedConcurrentExecutions: 5

Resources:
  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Ref Environment
      CorsConfiguration:
        AllowMethods:
          - "*"
        AllowOrigins:
          - Fn::ImportValue: !Sub backend-${Environment}-client-domain
      Auth:
        Authorizers:
          BasicAuthorizer:
            AuthorizationScopes:
              - email
            IdentitySource: "$request.header.Authorization"
            JwtConfiguration:
              issuer:
                - Fn::ImportValue: !Sub backend-${Environment}-issuer
              audience:
                - Fn::ImportValue: !Sub backend-${Environment}-user-pool-client-id

  DataPointsCreateRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: backend-data-points-create-role
      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

  DataPointsCreateFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub backend-${Environment}-data-points-create-function
      Role: !GetAtt DataPointsCreateRole.Arn
      CodeUri: ./../c-crop-backend/data_points/create
      Handler: handler.handler
      Events:
        RootGet:
          Type: HttpApi
          Properties:
            Auth:
              Authorizer: BasicAuthorizer
            Path: /simple
            Method: get
            ApiId: !Ref HttpApi

What am I doing wrong?

I'm deploying it with SAM CLI.

Thanks,

Thomas

@rockey5520
Copy link
Author

rockey5520 commented Jun 15, 2022

Hey @tbenhamou

I can give you template structure that worked for me, if you like to adjust yours and see if it helps

https://gist.github.com/rockey5520/82a32603ea096621be524f2816da98c2

Hope it works

@tbenhamou
Copy link

Hey @rockey5520 ,

Thanks for assisting me! Your template helped me for some other stuff but I found my issue just a few minutes ago!!!
The issuer field within the HttpApi resources should be a string and not a list of string. The deployment didn't failed on that.
How did I find out?
I tried to deploy a separated Authorizer and there the deployment did fail on the bad format of the value supplied!

BTW, The field issuer and audience should be in lowercase within the AWS::Serverless::HttpApi resource but if it's an AWS::ApiGatewayV2::Authorizer, it should be Issuer and Audience...

Thank you!

@jfuss jfuss changed the title Unable to set authorizer on AWS::Serverless::HttpApi Unable to set authorizer on AWS::Serverless::HttpApi on $default path Aug 31, 2022
@jfuss
Copy link
Contributor

jfuss commented Aug 31, 2022

This is a request on the SAM Spec not CLI. Moving to the correct repo (to make it easier to track) and updated the title to reflect the request.

@jfuss jfuss transferred this issue from aws/aws-sam-cli Aug 31, 2022
jneeee added a commit to jneeee/taskbox that referenced this issue Dec 4, 2022
jneeee added a commit to jneeee/taskbox that referenced this issue Dec 4, 2022
jneeee added a commit to jneeee/taskbox that referenced this issue Dec 4, 2022
@ruminize
Copy link

Just FYI for anyone getting here with
sam cli -v 1.9

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-httpapi-oauth2authorizer.html

Properties issuer and audience are case insensitive and can be used either lowercase as in OpenAPI or uppercase Issuer and Audience as in AWS::ApiGatewayV2::Authorizer.

For my issue with Authorizer not showing up, I had to update SAM CLI as well as change Audience to a list as in...

  Auth:
    Authorizers:
      TestAuth:
        IdentitySource: $request.header.Authorization
        JwtConfiguration:
          Issuer: https://cognito-idp.us-east-1.amazonaws.com/.....
          Audience:
            - 355.......
    DefaultAuthorizer: TestAuth

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

No branches or pull requests

10 participants