Poor man's kill switch for your demo applications
Tags: beginners, tutorial, aws, showdev
Published: 2020-01-02 13:02:05

---
title: Poor man's kill switch for your demo applications
published: true
description: expose a public endpoint for a live demo, while giving you the peace of mind that in case of misuse, the api will kill the requests keeping your costs low.
tags: beginners,tutorial,aws,showdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/0mhoej5s3p5yduwvwbcn.jpg
---

Today I want to share with you a little trick I learned a while back.  
You have just finished building your website or service and it is ready to be demo-ed. Maybe you want to present it to your colleagues, write a blog post about it or just get feedback.
Whatever the reason, you need to have the prototype publicly available on the Internet, but you are worried that could be misused. 

All it takes is someone who forgets to define the exit condition in the for loop. And...also, you know...not everybody on the internet is well intended.

```golang
for {
  response, e := http.Get("https://my-demo-service/")
}
```

Ofcourse, you do not want to be broke just to show your service. 
To prevent the service to be overwhelmed by requests and save a few bucks, we can use a kill switch, or as I like to call it: ___the poor  man's kill switch___.

It allows to expose a public endpoint for a live demo, while giving you the peace of mind that in case of misuse, the api will kill the requests keeping the your costs very low. This is possible thanks to API gateway cost model: [throttle requested are not considered in the billing](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html) :)

------------------------------------------------
Throttling is a process which limits the number of requests directed to an Api by consumers during a given period.
A common algorithm used to throttle request is the [token bucket algorithm](https://en.wikipedia.org/wiki/Token_bucket). In a nutshell, you have an initial bucket with tokens.
The amount of tokens represents the number of concurrent requests allowed in the system at any given moment. When a new request arrives, the algorithm removes a token from the bucket.
When the request has been processed (i.e. response has been sent back to the caller), the algorithm inserts back the token in the bucket. If the bucket has no token, requests are denied immediately.

___Throttling is the first step to protect our API. But for a demo application, this is not enough.___  
For example, you might set the throttling limit to 1000 requests/second. If anyone abuses the Api, you might still end up paying quite a few bucks. 
AWS Api Gateway for example, you would pay about $30 per month. Of course you will have also all the costs associated with your backend (EC2, Lambda, or any other compute option), the storage, etc, thus in reality the cost might higher than that.

I say it's too much to show a live demo in a Github project.  
___Let's see how can we use throttling to shut down our api when we detect that something fishy is going on.___


### The service
In the following example, I am going to pretend I have a service built on AWS. If you you use a different cloud provider, you need to check if they bill for throttled requests.

The service use AWS Api gateway to expose a Lambda function backend. All the code in this example is in [github.com/napicella/examples/kill-switch-lambda](https://github.com/napicella/utils/tree/master/examples/kill-switch-lambda)


### Kill switch mechanics
We will create an alarm on the number of requests received by the Api Gateway. The alarm triggers a lambda function which sets the throttling rate to zero, thus denying all the requests. As mentioned, Api Gateway does not charge for throttle requests, thus we won't pay for any further request.
The alarm is set to also send us an email to notify the event.
The CloudWatch alarm and the Lambda are be defined in a Cloud Formation template.

### Cloudwatch alarm 
The alarm triggers if the Api Calls are above the limit we provide (in the example we set it to be 100).
We also add a default subscription which is responsible to send an email to our email address. 

```yaml
Parameters:
  ApiGatewayApiName:
    Type: String
    Description: Exported key for the Api Gateway ApiName to use as metric source for the alarm(s)

Resources:
  LambdaErrorAlarm:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: 'API Gateway calls'
      Namespace: 'AWS/ApiGateway'
      MetricName: Count
      Dimensions:
      - Name: ApiName
        Value:
          Fn::ImportValue:
            !Sub "${ApiGatewayApiName}"
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 100
      ComparisonOperator: GreaterThanOrEqualToThreshold
      AlarmActions:
        - Ref: "AlarmNotificationTopic"
      TreatMissingData: notBreaching

  AlarmNotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
      - Endpoint: "some-email@gmail.com"
        Protocol: email
```

### Lambda function definition
In another template we define the Lambda function and we subscribe it to the topic created earlier; this is why the template takes as parameter the ___TooManyRequestAlarmTopic___.
We could have defined everything in a single template, but it's common practice to have alarms in their own template.


```yaml
Parameters:
  TooManyRequestAlarmTopic:
    Type: String
  ApiGatewayId:
    Type: String
  ApiGatewayStage:
    Type: String

Resources:
  apigatewayauthorizernodejs:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs12.x
      CodeUri: ./src
      Description: 'Kill switch'
      MemorySize: 256
      Timeout: 5
      Role: !GetAtt apigatewayauthorizernodejsRole.Arn
      Environment:
        Variables:
          API_GW_ID: !Sub "${ApiGatewayId}"
          API_GW_STAGE: !Sub "${ApiGatewayStage}"
      Events:
        TooManyRequestAlarm:
          Type: SNS
          Properties:
            Topic: !Sub "${TooManyRequestAlarmTopic}"


  apigatewayauthorizernodejsRole:
    Type: AWS::IAM::Role
    ##  omitted for brevity, see Github for the template
```

Finally, the code for the Lambda function which updates the Api Gateway with the new throttling parameters


```javascript
const AWS = require('aws-sdk'); 

const apigateway = new AWS.APIGateway({apiVersion: '2015-07-09', region: process.env.AWS_REGION});
var params = {
    restApiId: process.env.API_GW_ID,
    stageName: process.env.API_GW_STAGE,
    patchOperations: [{
        op: 'replace',
        path: '/~1*/*/throttling/rateLimit',
        value: '0'
    }]
};
console.log(`Kill switch for ${params.restApiId} - ${params.stageName}`);

const handler = (event, context, callback) => {

    apigateway.updateStage(params, function(err, data) {
        if (err) {
            console.log(err, err.stack);
            callback(err);
        } else {
            console.log("All the request will be throttled");
            callback(null, {
                statusCode: 200,
                body: JSON.stringify({message : "All the request will be throttled!!"})
            });
        }
    });

}

module.exports = { handler };
```

### Conclusions
This is all for now. Remember to set the default throttling limits and add a kill switch to your next demo project! Cheers!


Liked the article? [Share it on Twitter](https://twitter.com/intent/tweet?text=Poor's man kill switch for your demo applications.%20%40napicellatwit%0A%0Ahttps://dev.to/napicella/poor-s-man-kill-switch-for-your-demo-applications-4bo2)

----------------------------------------

Credit for the image to [TheDigitalArtist](https://pixabay.com/users/thedigitalartist-202249/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=683823)