Servlerless Secured API

By Marcin Piczkowski Comment
Subscribe

This is a continuation of the Serverless Reservation application started in previous posts.

There should be nothing simpler than securing the API with API key passed in request header. Servlerless documentation states that it already supports it without additional coding. All we need to do is to update handler definition in serverless.yml

functions:
  graphQl:
    handler: index.graphql
    memory: 512
    timeout: 3
    events:
      - http:
          path: graphql
          method: post
          private: true

We’ve just added private: true. This tells Serverless to expect API key in header. How do we set which key to use? Again, we need to update serverless.yml

provider:
  name: aws
  runtime: nodejs4.3
  stage: dev
  profile: dev_profile
  apiKeys:
    - secret

We have added apiKeys param in the provider definition, secret is the name of the key. If we had multiple API keys we could identify them by name and distribute to multiple users so that each of them has own key.

The header which clients should pass in each request must be always x-api-key because Amazon does not support custom names at the moment - see this discussion.

Let’s test it.

We will use the code developed in previous blogpost. When we deploy the application it will print out the generated value for the API key to use in header. The same we can get with command:

sls info

wich gives information like:

...
api keys:
  secret: rKGHEryMVF6EvmXF4VzGzSv1xy7Jk3d7KjREL5Fg
...

Then we use Curl to test it:

  • without API key
curl -X POST \
-H "Content-Type: application/json" \
-d '{items(name: "demo item") {name, createdAt}}' \
<endpoint URL>

In the above command we need to replace <endpoint URL> with the real URL of API Gateway which should be printed out from the serverless deploy command.

The response which we should get is: Forbidden

  • with API key
curl -X POST \
-H "Content-Type: application/json" \
-H "x-api-key: rKGHEryMVF6EvmXF4VzGzSv1xy7Jk3d7KjREL5Fg" \
-d '{items(name: "demo item") {name, createdAt}}' \
<endpoint URL>

Booo..! this time we get the same error. It does not work. There is an open issue already. We need extra manual work to add the API key created in CloudFormation by Serverless framework to usage plan. This page explains very well how to configure Usage Plan on AWS.

When we login to AWS console and navigate to API Gateway panel we can see that our API Key is already present

image

but Usage Plan is empty so we need to create it.

image

Here is how we do it:

  1. Click Create button and fill in the form
image

Click Next.

  1. Choose API and Stage - we have only one of each so it should not be confusing.
image

We cannot continue further because the little orange triangle next to selected API shows an error that not all resources in the API are secured with a key. This is because our former /hello endpoint is not secured. As we’re not going to need it anymore we can just delete it and come back to Usage Plan creation.

Go to Resources, select ‘/hello’ and in Actions dropdown select ‘Delete Resource’

image

Then come back to Usage Plan and assign API to Stage again

image

This time it succeeds. Then go to second tab and select API key.

image

Now we should be able to request endpoint successfully, check again:

curl -X POST \
-H "Content-Type: application/json" \
-H "x-api-key: rKGHEryMVF6EvmXF4VzGzSv1xy7Jk3d7KjREL5Fg" \
-d '{items(name: "demo item") {name, createdAt}}' \
<endpoint URL>

The code for this post can be found at Github

References

comments powered by Disqus