Sep 29, 2020
Design on a dime: How we built a license-key generator using AWS serverless architecture
As with any company producing software for commercial use, we want to protect it from unauthorized access and prevent it from being pirated. This is typically done through a license key mechanism. Until recently, we were creating and managing our customers’ license keys manually.
So the request came down to us to find the easiest and most cost-effective way for Imply employees to generate these license keys themselves. We needed something that people from sales and marketing could use without having to VPN in or run a script.
The requirements we scoped were as follows:
- Access to the private key must be under strict control
- No user should be able to view the contents of the private key
- All uses of the private key must be audited
- License keys must be stored in a secure central repository with strict access controls
We decided to build the service ourselves, as there aren’t that many available off the shelf. Also, having the private key held by a third party somewhat defeats the object.
In deciding which architecture to use, we looked at the assumed traffic for the service. While some services may need to handle high throughput or sustainable traffic all day, our licensing service would be used relatively infrequently. A licensing service isn’t something that requires constant access by a user.
In light of all this unused CPU time, a serverless architecture looked attractive. It’s easy to use, has implicit high availability, and is self auto-scaling and -provisioning.
Imply is currently a heavy AWS shop, so we decided to go with AWS serverless functionality using the following components:
- AWS API Gateway for the REST API
- AWS Lambda for business logic
- AWS Key Management Service (KMS) to manage our asymmetric key and run cryptographic algorithms
- AWS Cloudwatch for system logging and asymmetric key usage auditing
- AWS DynamoDB for license key storage
Here’s a diagram of the full system:
And here are the steps our employees take to create the license keys:
- Client authenticates with Okta
- Client sends request with auth token to licensing REST API hosted on API Gateway
- API Gateway sends the auth token to a Lambda authorizer function
- Lambda authorizer validates the token with Okta
- API Gateway invokes a lambda function to generate a license key
- Lambda function uses data sent in the REST payload to generate a message and signs the message using a private key within KMS
- License key generation request is logged to CloudWatch for auditing purposes
- License is stored in DynamoDB
We used OpenID Connect to authenticate users and give them access to the system. Not everybody at Imply can just go in and create a license; you have to be in a certain user group.
For storage, we had a few different options. You can of course use your MySQL database, but our use cases didn’t really require full SQL. So we went with DynamoDB, as it’s cost-effective and easy to use with Lambda.
One thing we may want to add to the service later that we don’t currently have is remote authentication. At the moment we use a local verification scheme that requires a public key.
Overall, this system has given us exactly what we wanted and has been really easy to create. We have the private keys stored securely, we can audit all their uses, store all licenses, and provide fine-grain control of who can access them via Okta. All this at very low cost.