Skip to content

Latest commit

 

History

History
37 lines (20 loc) · 5.21 KB

README.md

File metadata and controls

37 lines (20 loc) · 5.21 KB

Serverless Websockets

Many modern web applications benefit from persistent connections between the client and server, and the Websockets protocol is a popular implementation of this. Integrating Websocket connections into a scalable or serverless architecture can be challenging, however. The most common implementations on Amazon Web Services infrastructure involve using an Nginx or Apache proxy server, in an Elastic Load Balancing cluster or Elastic Beanstalk application; this involves a lot of unmanaged infrastructure, and makes delivering a push to one particular target challenging - how do you identify which server in an elastic cluster is holding the connection that you want to push to?

This is an implementation of a Websockets pipeline using the AWS Internet of Things and Security Token Services. The IoT framework is intended to support devices to communicate via the lightweight MQTT protocol; but the Javascript SDK provides an implementation of this via Websockets. STS allows us to provide clients with bespoke, limited credentials to access an account's IoT service and send/receive messages that are passing over the MQTT message broker.

Implementation

alt tag

This implementation is based on Diego Zanon's Serverless system, but has been rebuilt to use more generic frameworks. Due credit for the concept, though, even if not the code.

The IoT message broker service is a sort of 'conversation cloud': devices can subscribe to any topic identifier (or a wildcarded partial match) and publishers can send messages to any topic they choose. In order to bring this system more in line with the single-channel Websocket system, therefore, we have to restrict which topics a given client can subscribe to.

The CloudFormation script serverless-websockets.template creates an API Gateway to a Lambda function, plus a 'client' IAM Role. When a client calls the Lambda function via an HTTP POST request, the Lambda uses the Security Token Service to generate time-limited credentials for the client role. In the process, the Lambda applies additional restrictions on the permissions that the resulting keys have, meaning that they can only be used to connect to the IoT service with a particular client ID and to subscribe to particular topics. It then returns these keys to the client.

The client can then use these credentials to connect to the IoT service and subscribe to the topics that they are interested in. You can use the AWS-supported IoT Device SDK for JavaScript for this. This can be bundled into a Node application or run independently; the file aws-iot-device-sdk.js is generated by running browserify -g aws-iot-device-sdk.js, and can be used as a standalone library.

The files index.html and demo.js illustrate a simple use of the system on the client side. If you subscribe to a unique topic per client (eg by using the client ID in the topic name) then you effectively get a traditional one-to-one Websocket connection between client and server. If you use a common name, clients can pass messages between each other or a server can push the same message to a group of clients with one command.

Publishing to a client can be done server-side using the AWS CLI:

root@sandbox:~# aws iot-data publish --topic allowed/client_abcdef12 --payload=Hi!

Or the equivalent implementation in the Amazon SDK. You can allow your clients to publish messages too; you'll need to add the iot:Publish permission to both the client Role and the permissions restriction in the Lambda function.

Costs

Since all the infrastructure is stateless and managed, you pay only for active use. The Lambda function takes ~1s to run (our authentication logic doesn't make any additional network calls). Lambda, API Gateway and IoT all have free tiers that can accommodate ~250,000 messages/month, although the IoT and API Gateway tiers expire after 12 months. Even without the free tiers, costs per user are extremely low, in the range of dollars per month for thousands of users (almost all of which is the charge per IoT message transmitted).

Extensions

You'll need to customise the Lambda function and client-side code to pass, and verify, some authentication credentials before allowing them to connect to your message broker. It would fit best with the stateless/serverless model if this took the form of a token such as JWT which can be verified without needing to query a user database or other stateful system.

Amazon SNS already has good support (via SNS Mobile Push) for sending push notifications directly to native apps using various vendor-specific protocols. You wouldn't want to reinvent those wheels. But IoT Topics and SNS Topics can be easily bridged using an IoT Topic Rule for the IoT→SNS direction, and a Lambda function ()which consumes the SNS and republishes to IoT) for the SNS→IoT direction.