# Using Serverless Frameworks

Serverless has become a movement in application development because it allows developers to focus on code and leave infrastructure to the providers, e.g. Amazon Web Services (AWS). It is important to consider a secure architecture when using Serverless because, although the provider provides security features, the use of security is the responsibility of the developer. This article will focus on how to get started with Serverless using Amazon Web Services.

## What is Serverless?

[Serverless](https://serverless.com/) is an infrastructure framework to deploy your application code and application framework without having to provision any servers, whether physical or virtual. Traditionally you would deploy a server, install and configure an operating system, install and configure required software (e.g. PHP, Python, Java), install a database (e.g. MySQL or MongoDB), setup an application framework (e.g. Laravel PHP, Ruby on Rails), and configure your server to be accessible on the Internet. That's a lot of work! With Serverless you can get going within minutes.

With Serverless you can run your application as functions; this concept is called Microservices. Rather than deploying a large application that is deployed together and needs to be maintained together, you can deploy functions which can be maintained individually. For example, you can have the following functions in your basic application: create account, verify account, verify login, retrieve user information, etc. When create account functions needs to be updated, you update that function without affecting the other functions. The create account function becomes its own service, and the other functions are also their own services.

In addition to functions, you can setup databases, authorization, and other Serverless infrastructure depending on your provider. This is done by updating your Serverless configuration.

## An Example of a Very Simple Serverless Configuration

You use a Serverless file that defines your infrastructure you plan to setup (i.e. deploy) to your provider.

Observe the example `serverless.yml` configuration below.

```yaml
service: simple

frameworkVersion: ">=1.26.1"

provider:
    name: aws
    runtime: nodejs8.10
    product: myproduct
    stage: dev
    region: us-east-1

    iamRoleStatements:
    - Effect: Allow
        Action:
        - lambda:InvokeFunction
        Resource: "*"

functions:
    helloWorld:
    handler: functions/helloWorld/handler.index
    events:
        - http:
            path: v1/helloWorld
            method: get
```

You then use the `serverless` [command line tool](https://serverless.com/framework/docs/providers/aws/guide/installation/) by deploying the configuration.

```sh
cd simple
serverless deploy
```

**Note:** You can use the shortcut `sls` which is short for `serverless`. Future commands will use `sls`.

When this is deployed, it will create the following:

* S3 bucket containing the configuration for my service
* API Gateway to route the `get` and `post` events to the `helloWorld` Lambda
* The `helloWorld` Lambda function containing the Node code from `src/helloWorld/handler.index`
* CloudWatch logs to capture events for the `helloWorld` function

You will be able to make an HTTP GET request to an address such as `https://004ueoizyd.execute-api.us-east-1.amazonaws.com/dev/v1/helloWorld`.

When you make the request, the following occurs:

![HTTP GET Request via the API Gateway](https://www.secjuice.com/content/images/2018/11/image-1.png)

*HTTP GET Request via the API Gateway*

### Adding a Custom Domain Name

You are probably wondering how you can use a custom domain name, e.g. myapp.com, instead of the automatically generated address. Yet, it can be done.

Add the `serverless-domain-manger` plugin to your configuration:

```sh
npm install serverless-domain-manager
```

Update your Serverless configuration

```yaml
service: simple

frameworkVersion: ">=1.26.1"

provider:
    name: aws
    runtime: nodejs8.10
    product: myproduct
    stage: dev
    region: us-east-1

    iamRoleStatements:
    - Effect: Allow
        Action:
        - lambda:InvokeFunction
        Resource: "*"

functions:
    helloWorld:
    handler: functions/helloWorld/handler.index
    events:
        - http:
            path: v1/helloWorld
            method: get

plugins:
    - serverless-domain-manager

custom:
    customDomain:
    domainName: api.mydomain.com
    certificateName: api.mydomain.com
    basePath: simple
    stage: dev
    createRoute53Record: true
```

You will need to add the certificate to AWS to finish this setup. I am excluding the instructions and leaving it to the reader to further explore. To learn more about plugins, read the [Installing Plugins at the Serverless](https://serverless.com/framework/docs/providers/aws/guide/plugins/) web site.

I am going to use the automatically generated addresses in this article.

## Adding Security at the API Gateway

The example above does nothing to limit access to the Lambda function. This is acceptable if the Lambda function does nothing sensitive and return public information. If the Lambda function returns sensitive data, e.g. customer data, or performs a sensitive function, e.g. deleting a customer account, needs to be protected through authorization. The API Gateway can be configured to require authorization before the lambda is executed.

![API Gateway Authorization](https://www.secjuice.com/content/images/2018/11/image-2.png)

*API Gateway Authorization*

The above diagram shows an example of the API Gateway authorization capability. It uses another lambda which does the authorization. If the authorization is successful, then the lambda function is executed. Otherwise, the API Gateway denies the request.

The authorizer should be as secure as your application needs. The OWASP Top 10 recommends using JSON Web Tokens (JWT) as the method for using authentication tokens. The JWT approach can be used in authorizer lambda.

To keep things simple, I am going to use a static authorization key instead of a rotating token.

A new file is added at `authorizers/staticKeyAuthorizer/handler.js`.

```js
'use strict';

const AuthPolicy = require('./AuthPolicy');
const STATIC_KEY = 'mysecurekey';

module.exports.index = (event, context, callback) => {
    console.log('Client token:', event.authorizationToken);
    console.log('Method ARN:', event.methodArn);

    if (STATIC_KEY != event.authorizationToken) {
        callback('Unauthorized');
    }

    const apiOptions = {};
    const tmp = event.methodArn.split(':');
    const apiGatewayArnTmp = tmp[5].split('/');
    const awsAccountId = tmp[4];
    const region = tmp[3];
    const restApiId = apiGatewayArnTmp[0];
    const stage = apiGatewayArnTmp[1];

    const policy = {
        "principalId": "SIMPLE",
        "policyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": "execute-api:Invoke",
                    "Effect": "Allow",
                    "Resource": `arn:aws:execute-api:${region}:${awsAccountId}:${restApiId}/${stage}/*`
                }
            ]
        }
    }

    callback(null, policy);
};
```

The `serverless.yml` configuration is updated to add the authorizer.

```yaml
service: simple

frameworkVersion: ">=1.26.1"

provider:
    name: aws
    runtime: nodejs8.10
    product: myproduct
    stage: dev
    region: us-east-1

    environment:
    STATIC_KEY: mysecurekey

    iamRoleStatements:
    - Effect: Allow
        Action:
        - lambda:InvokeFunction
        Resource: "*"

functions:
    authorizerStaticKey:
    handler: authorizers/staticKeyAuthorizer/handler.index
    helloWorld:
    handler: functions/helloWorld/handler.index
    events:
        - http:
            path: v1/helloWorld
            method: get
            authorizer:
            name: authorizerStaticKey
            resultTtlInSeconds: 0
            identitySource: method.request.header.STATIC_KEY
```

From now on the HTTP request needs to have the header `STATIC_KEY: mysecurekey` in order for the `helloWorld` lambda to execute.

## A Simple Serverless Architecture

Thus ends Part One of my Serverless Series, in my next article, you will learn about different architectures to employ for a simple use case.

The simple use case is depicted below.

![Simple serverless architecture.](https://www.secjuice.com/content/images/2018/11/image-15.png)

*Simple serverless architecture.*

## Source

The source files are available at [https://github.com/miguel-a-calles-mba/secjuice/tree/master/serverless-simple-example](https://github.com/miguel-a-calles-mba/secjuice/tree/master/serverless-simple-example) for your enjoyment.

## Before you go

%%[mailing-list]

### About the author

%%[bio]

<hr>

*Originally published on [Secjuice.com](https://www.secjuice.com/using-serverless-part1/)*

*Image by [crystal](https://dribbble.com/cryss) on [Dribbble](https://dribbble.com/)*
