aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.5k stars 1.17k forks source link

sam local start-api Missing Authentication Token for root path '/' #437

Closed 0xdevalias closed 4 years ago

0xdevalias commented 6 years ago

Description:

When I run sam local start-api -s public/ and try to access my endpoint, I receive a Missing Authentication Token in the browser. This same code runs fine when deployed to lambda, and correctly exposes my endpoint without auth required.

FOO:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub ${AWS::StackName}-FOO
      CodeUri: ./target
      Handler: foo
      Runtime: go1.x
      Tracing: Active
      Events:
        CatchAll:
          Type: Api
          Properties:
            Path: "/{proxy+}"
            Method: ANY

Observed result:

Missing Authentication Token

Expected result:

My API is exposed without auth.

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

macOS

Output of sam --version:

SAM CLI, version 0.3.0

0xdevalias commented 6 years ago

Starting from scratch for debug:

sam init --runtime go1.x
cd sam-app
dep init
GOOS=linux GOARCH=amd64 go build -o hello-world/hello-world ./hello-world
sam local start-api

Attempting to access http://127.0.0.1:3000/ I see Missing Authentication Token (with no endpoint mapped there) Attempting to access http://127.0.0.1:3000/hello it works as expected.

Changing the HelloWorldFunction to use /{proxy+}:

HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/
      Handler: hello-world
      Runtime: go1.x
      Tracing: Active # https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html
      Events:
        CatchAll:
          Type: Api
          Properties:
            Path: "/{proxy+}"
            Method: ANY
      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

Now when I access http://127.0.0.1:3000/anythinghere it continues to work as expected.. so I don't think that is my issue.

Edit: Digging a little deeper.. it looks like even if I explicitly set the path to Path: "/" I get the same Missing Authentication Token when trying to access it. I wonder if that is somehow playing into this issue, even when trying to proxy it?

Edit2: Additional context, using https://github.com/gorilla/mux + https://github.com/awslabs/aws-lambda-go-api-proxy internally. When I set the path to Path: "/example" in my main project, that 1 endpoint works properly and doesn't produce Missing Authentication Token. When it is set to proxy though, my code never even gets reached/started. If I set my project to Path: "/a/{proxy+}" and try to access any of the URLs, my code starts correctly (then gets a 404 because that route doesn't exist)

terrywarwar commented 6 years ago

I'm getting the same error with SAM CLI, version 0.4.0. It doesn't look like it's routing to the static files in my case.

2018-06-20 14:50:36 Mounting static files from /Users/terry/go/src/app/public at /
2018-06-20 14:50:36 Mounting SampleFunction at http://127.0.0.1:3000/api/{proxy+} [GET, DELETE, PUT, POST, HEAD, OPTIONS, PATCH]
2018-06-20 14:50:36 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2018-06-20 14:50:36  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
2018-06-20 14:50:42 127.0.0.1 - - [20/Jun/2018 14:50:42] "GET / HTTP/1.1" 403 -
2018-06-20 14:50:42 127.0.0.1 - - [20/Jun/2018 14:50:42] "GET /favicon.ico HTTP/1.1" 403 -
terrywarwar commented 6 years ago

Shouldn't localhost:3000 -> serves the index.html?

jfuss commented 6 years ago

So this is an issue with Flask and how the endpoints are modeled. By default Flask does not resolve the / as apart of the /{proxy+} route. This means we need to handle / (the root path) separately. There maybe a way to configure this behavior by default but haven't investigated that deeply yet.

@terrywarwar

Shouldn't localhost:3000 -> serves the index.html?

Maybe? But SAM CLI can't since we support API to Lambda on the same root path, so there can be path conflicts. Instead, you should just add the /index.html to the path explicitly.

Marking this as a bug

amcp commented 6 years ago

I am getting this issue only on GET calls. POST works fine.

tomasaschan commented 5 years ago

@amcp I'm seeing the opposite; GET works fine, while POST yields this error. None of my paths are /, i.e. I'm GETting and POSTing to e.g. /foo and /bar.

Windows 10, SAM CLI version 0.7.0.

nealio82 commented 5 years ago

I'm experiencing the same. Using SAM local POST works fine, but GET returns the "missing authentication token" on all catch-all routes, unless I add the first part of the route into the template.yaml config.

eg:

using path: /{proxy+}, method: ANY

GET /api/books, and /api/books/[id] returns missing authentication token

whereas using path: /api/{proxy+}, method: ANY

GET /api/books, and /api/books/[id] work as expected

Both configurations appear to work normally once deployed to the cloud.

I think this is going to become more prevalent as an issue now the runtime API has opened new languages and frameworks up to Lambda, and more people are going to get on-board with developing serverless functions locally, expecting their chosen language / framework to handle routing for them.

MacOS, SAM CLI version 0.8.1

jfuss commented 5 years ago

@nealio82 While the results are the same, your issue is different than the original issue. I commented above on what this issue relates to.

Please open a separate issues so we can track and investigate separately.

nealio82 commented 5 years ago

@jfuss Ok, shall do :) Although I'm not sure that it is different? Looking at the original bug report by @0xdevalias it looks like the config is almost exactly the same as the config I have, and their experience is the same... (the only difference I can see is that I also have path: / configured in my template.yaml to match the / route, and @0xdevalias doesn't)

jfuss commented 5 years ago

@nealio82 You didn't state anything about a root path (/) being configured. Your statement makes it sound like /{proxy+} is causing other paths not to resolve.

nealio82 commented 5 years ago

Ah, sorry, I didn't think it was relevant - I was adding context to the fact I'm seeing the same as the OP, and I didn't want to simply add an unhelpful '+1' or 'me too' comment. The root path works OK, as implied by 'GET returns the "missing authentication token" on all catch-all routes'.

metaskills commented 5 years ago

I had opened #1037 and closed it because I think this is the root issue. Thanks!

dpeek commented 5 years ago

So I think I might have found a way to fix this – commenting out the static files config passed to flask here allows /{proxy+} paths to resolve.

Happy to put together a PR, but not sure what you want to do... while serving static files is useful it's not something that APIG does and users can achieve something similar with a lambda serving files at a specific route.

If you want to avoid a breaking change, seems like path of least change is to only pass this config to flask if the user specifies the --static-dir argument?

dpeek commented 5 years ago

Erm, scratch that. Was switching between samdev and sam and it seems my issue sorted it self out and now /{proxy+} resolves fine. Ignore me!

metaskills commented 5 years ago

Not for me.

metaskills commented 5 years ago

CONFIRMED! Setting static_url_path=None in local_apigw_service.py does allow /{proxy+} to work. I have confirmed with Flask that these two options are incompatible. I think it is important that local development allow root proxy and serving static files from root needs to be re-considered. What do other's think?

StoneCypher commented 5 years ago

it's amusing because this breaks your front page hello world example as generated by your kit

StoneCypher commented 5 years ago

it's actually pretty concerning that nine months after you found out your baseline generated code doesn't serve root correctly, it's still an outstanding bug

that's a one-liner route fix in flask

metaskills commented 5 years ago

Well in fairness, they have done ALOT of work and if I had to pick, I'd say I appreciate the effort being able to run Ruby on Lambda and other things vs something I can hack locally that is not an issue when deployed. That said, would be nice to see fixed.

kaihendry commented 5 years ago

I followed https://github.com/stackery/php-lambda-layer to also get this "Missing Authentication Token". I've read this and I'm non-the-wiser.

Is there an error with https://media.dev.unee-t.com/2019-04-04/template.yaml ?

SAM CLI, version 0.14.2

Must say the SAM cli is a bit rough around the edges. Why can't it print the endpoint in the CLI? zomg. https://s.natalian.org/2019-04-04/1554348366_2560x1440.png

dorneanu commented 5 years ago

Hi,

are there any updates on this one? I have exactly the same issue.

iceback commented 5 years ago

THIS IS A MACOS VERSION OF #1316 kitselas:~$ sam --version SAM CLI, version 0.18.0 kitselas:bin root# docker --version Docker version 19.03.1, build 74b1e89

begin: template.yaml Transform: 'AWS::Serverless-2016-10-31' Resources: PedigreesFunction:

This resource creates a Lambda function.

Type: 'AWS::Serverless::Function'

Properties:
  # This function uses the Nodejs v8.10 runtime.
  Runtime: python3.7

  # This is the Lambda function's handler.
  Handler: app.lambdb_handler

  # The location of the Lambda function code.
  CodeUri: ./lambda-scripts/get-pedigrees.py

  # Event sources to attach to this function. In this case, we are attaching
  # one API Gateway endpoint to the Lambda function. The function is
  # called when a HTTP request is made to the API Gateway endpoint.
  Events:
    PedigreesApi:
        # Define an API Gateway endpoint that responds to HTTP GET at /thumbnail
        Type: Api
        Properties:
            Path: /pedigrees
            Method: GET

end template.yaml sam validate 2019-08-08 10:56:23 Found credentials in shared credentials file: ~/.aws/credentials /Users/rjs3/utah/dev/aws/pprapp/PPRConsole/template.yaml is a valid SAM Template

hit localhost:3000/pedigrees

kitselas:PPRConsole$ sam local start-api 2019-08-08 10:57:41 Mounting PedigreesFunction at http://127.0.0.1:3000/pedigrees [GET] 2019-08-08 10:57:41 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template 2019-08-08 10:57:41 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit) 2019-08-08 10:58:38 Invoking app.lambdb_handler (python3.7) 2019-08-08 10:58:39 Found credentials in shared credentials file: ~/.aws/credentials

Fetching lambci/lambda:python3.7 Docker container image...... 2019-08-08 10:58:40 Mounting /Users/rjs3/utah/dev/aws/pprapp/PPRConsole/lambda-scripts/get-pedigrees.py as /var/task:ro,delegated inside runtime container 2019-08-08 10:58:41 Exception on /pedigrees [GET] Traceback (most recent call last): File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/api/client.py", line 261, in _raise_for_status response.raise_for_status() File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/requests/models.py", line 940, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: http+docker://localhost/v1.35/containers/f0123288c45dd08164d6cf5ca4d3d598984a0d2213263c35dc671c254948013f/start

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/app.py", line 2317, in wsgi_app response = self.full_dispatch_request() File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/app.py", line 1840, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/app.py", line 1743, in handle_user_exception reraise(exc_type, exc_value, tb) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/_compat.py", line 36, in reraise raise value File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/app.py", line 1838, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/flask/app.py", line 1824, in dispatch_request return self.view_functionsrule.endpoint File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/samcli/local/apigw/local_apigw_service.py", line 156, in _request_handler self.lambda_runner.invoke(route.function_name, event, stdout=stdout_stream_writer, stderr=self.stderr) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/samcli/commands/local/lib/local_lambda.py", line 93, in invoke self.local_runtime.invoke(config, event, debug_context=self.debug_context, stdout=stdout, stderr=stderr) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/samcli/local/lambdafn/runtime.py", line 86, in invoke self._container_manager.run(container) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/samcli/local/docker/manager.py", line 98, in run container.start(input_data=input_data) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/samcli/local/docker/container.py", line 189, in start real_container.start() File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/models/containers.py", line 392, in start return self.client.api.start(self.id, *kwargs) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/utils/decorators.py", line 19, in wrapped return f(self, resource_id, args, **kwargs) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/api/container.py", line 1091, in start self._raise_for_status(res) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/api/client.py", line 263, in _raise_for_status raise create_api_error_from_http_exception(e) File "/usr/local/Cellar/aws-sam-cli/0.18.0/libexec/lib/python3.7/site-packages/docker/errors.py", line 31, in create_api_error_from_http_exception raise cls(e, response=response, explanation=explanation) docker.errors.APIError: 400 Client Error: Bad Request ("OCI runtime create failed: container_linux.go:345: starting container process caused "process_linux.go:430: container init caused \"rootfs_linux.go:58: mounting \\"/Users/rjs3/utah/dev/aws/pprapp/PPRConsole/lambda-scripts/get-pedigrees.py\\" to rootfs \\"/var/lib/docker/overlay2/4248cf995aab0b8fb6cdd0db26dde5c5a99ccb31fce1c217a8c07cd8e6268704/merged\\" at \\"/var/lib/docker/overlay2/4248cf995aab0b8fb6cdd0db26dde5c5a99ccb31fce1c217a8c07cd8e6268704/merged/var/task\\" caused \\"not a directory\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type") 2019-08-08 10:58:41 127.0.0.1 - - [08/Aug/2019 10:58:41] "GET /pedigrees HTTP/1.1" 502 - 2019-08-08 10:58:41 127.0.0.1 - - [08/Aug/2019 10:58:41] "GET /favicon.ico HTTP/1.1" 403 -

I cannot locate the mounts under ~/Library/Containers

dorneanu commented 5 years ago

As @metaskills commented:

CONFIRMED! Setting static_url_path=None in local_apigw_service.py does allow /{proxy+} to work.

This did not work for me. :( My version is:

$ sam --version
$ SAM CLI, version 0.19.0
nevtum commented 4 years ago

By adding a root endpoint and another separate proxy endpoint to the SAM template I was able to get it to work:

...
Resources:
  MyFunction:
    Properties:
      CodeUri: MyFunction
      Events:
        RootEndpoint:
          Properties:
            Method: any
            Path: /
          Type: Api
        EverythingElse:
          Properties:
            Method: any
            Path: /{proxy+}
          Type: Api
      Handler: app.lambda_handler
      Runtime: python3.7
    Type: AWS::Serverless::Function

It seems like this convention of configuring multiple events for the same handler is done this way in other frameworks such as Zappa and Serverless (see the serverless.yml from this link).

c2tarun commented 4 years ago

Solution provided by @nevtum works for / path. Thanks @nevtum. I am closing this issue, if anyone have questions please feel free to re-open.

Kordstan commented 3 years ago

I am using CDK to create the apigateway and adding ResourceBase.addProxy and setting the anyMethod to true worked for me and I dont get the Missing Authentication...

abecks commented 3 years ago

The solution provided by @nevtum does not work while also using the static assets option by either specifying -s manually or having a public folder present in the SAM directory.

Any ideas on a static assets workaround? @c2tarun I think this should be reopened

randallb commented 9 months ago

I have a potential fix at #6376 if the maintainers are interested... happy to implement myself.