Solution components - Virtual Waiting Room on AWS

Solution components

Waiting room public and private APIs

The Virtual Waiting Room on AWS solution’s primary purpose is to control the generation of JSON Web Tokens (JWT) for clients in a controlled way to avoid bursts of new users that might overwhelm the destination website. The JWTs can be used for site protection, preventing access to web pages until the waiting room token is obtained, and also for API access authorization.

The core template installs a public API and private (IAM-authorized) API used for most Virtual Waiting Room on AWS operations. The public API is configured with a CloudFront distribution with multiple caching policies based on the API path. A DynamoDB table and EventBridge event bus are created. The template adds a new VPC with two Availability Zones (AZs), an Elasticache (Redis OSS) cluster in both AZs, and several Lambda functions. Lambda functions that interact with Elasticache (Redis OSS) have network interfaces within the VPC and all other Lambda functions have default network connectivity. The core APIs are the lowest layer of interaction with the solution. Other Lambda functions, Amazon Elastic Compute Cloud (Amazon EC2) instance, and containers can act as extensions and call the core APIs to build waiting rooms, control inlet traffic, and react to events generated from the solution.

In addition, the core stack creates an alarm for all of its Lambda function errors and throttle conditions, as well as alarms for each API Gateway deployment for 4XX and 5XX status codes.

Virtual Waiting Room on AWS public and private APIs component diagram

Virtual Waiting Room on AWS Public and private APIs component

  1. CloudFront distribution delivers public API calls for the client and caches result where appropriate.

  2. Amazon API Gateway public API process queue requests from the virtual waiting room, track the queue position, and support validation of tokens that allow access to the target website.

  3. SQS queue regulates traffic to the AWS Lambda function that processes the queue messages.

  4. The AssignQueueNum Lambda function validates each message in its batch received, increments the queue counter in Elasticache (Redis OSS), and stores each request in Elasticache (Redis OSS) with its associated queue position.

  5. The GetPublicKey Lambda function retrieves the public key value from Secrets Manager.

  6. The GenerateToken Lambda function generates a JWT for a valid request that has been allowed to complete its transaction at the target site. It writes an event to the waiting room’s custom event bus that a token has been generated. If a token has been previously generated for this request, no new token is generated.

  7. The GetQueueNumber Lambda function retrieves and returns the client’s numeric position in the queue from Elasticache (Redis OSS).

  8. The GetServingNumber Lambda function retrieves and returns the number currently being served by the waiting room from Elasticache (Redis OSS).

  9. The GetWaitingNum Lambda function returns the number currently queued in the waiting room and have yet to be issued a token.

  10. VPC endpoints allow Lambda functions in the VPC to communicate with services within the solution.

  11. Elasticache (Redis OSS) cluster stores all requests to enter the waiting room with a valid Event ID. It also stores several counters like number of requests enqueued, number currently being served, number of tokens generated, number of sessions completed, and number of sessions abandoned.

  12. API Gateway private API resources to support administrative functions. The private APIs are AWS IAM authenticated.

  13. The GetExpiredTokens Lambda function returns a list of request IDs with expired tokens.

  14. The AuthGenerateToken Lambda function generates a token for a valid request that has been allowed to complete its transaction at the target site. The issuer and the validity period of a token initially set during the core stack deployment can be overridden. It writes an event to the waiting room’s custom event bus that a token has been generated. If token has been previously generated for this request, no new token is generated.

  15. The IncrementServingCounter Lambda function increments the waiting room’s serving counter stored in Elasticache (Redis OSS) given an increment by value.

  16. The GetNumActiveTokens Lambda function queries DynamoDB for the number of tokens that have yet to expire, have not been used to complete its transaction, and have not been marked abandoned.

  17. The ResetState Lambda function resets all counters stored in Elasticache (Redis OSS). It also deletes and recreates the TokenTable, QueuePositionEntryTime, and ServingCounterIssuedAt DynamoDB tables. Additionally, it performs CloudFront cache invalidation.

  18. The UpdateSession Lambda function updates the status of a session (token) stored in the TokenTable DynamoDB table. Session status is denoted by an integer. Sessions set to a status of 1 indicates completed, and -1 indicates abandoned. It writes an event to the waiting room’s custom event bus that a session has been updated.

  19. The TokenTable DynamoDB table stores token data.

  20. The QueuePositionEntryTime DynamoDB table stores queue position and entry time data.

  21. The ServingCounterIssuedAt DynamoDB table stores updates to the serving counter.

  22. The GetQueuePositionExpireTime Lambda function is invoked when the client requests the remaining queue position expiry time.

  23. The SetMaxQueuePositionExpired Lambda function sets the maximum queue position that has expired corresponding to the ServingCounterIssuedAt table values. It runs every minute if the IncrSvcOnQueuePositionExpiry parameter is set to true during core stack deployment.

  24. The GenerateEvents Lambda function writes various waiting room metrics to the waiting room's custom event bus. It gets run every minute if the Enable Events Generation parameter is set to true during core stack deployment.

  25. AWS Secrets Manager stores keys for token operations and other sensitive data.

  26. Amazon EventBridge custom event bus receives an event every time a token is generated and a session is updated in the TokenTable DynamoDB table. It also receives events when the serving counter is moved in the SetMaxQueuePositionExpired Lambda. It gets written to with various waiting room metrics, if activated during core stack deployment.

  27. Amazon CloudWatch event rule is created if the Enable Events Generation parameter is set to true during core stack deployment. This event rule initiates the GenerateEvents Lambda function every minute.

Authorizers

The solution includes an API Gateway Lambda authorizers stack. The stack consists of one IAM role and a Lambda function. The APIGatewayAuthorizer Lambda function is an authorizer for API Gateway that can validate the signature and claims of a token issued by the Virtual Waiting Room on AWS API. The Lambda function supplied with the stack can be used to protect cloud APIs until a user has progressed through the waiting room and receives an access token. The authorizer automatically retrieves and caches the public key and configuration from the core API for token verification. It can be used without modification and can be installed in any AWS Region that supports AWS Lambda.

OpenID adapter

The OpenID adapter stack deploys an API Gateway and Lambda functions that act as an OpenID identity provider. The OpenID adapter provides a set of OIDC-compatible APIs that can be used with existing web hosting software that support OIDC identity providers, such as AWS Elastic Load Balancers, WordPress, or as a federated identity provider for Amazon Cognito or similar service. The adapter allows a customer to use the waiting room in the AuthN/AuthZ flow when using off-the-shelf web hosting software with limited integration options. The stack also installs a CloudFront distribution with one Amazon S3 bucket as an origin and another S3 bucket for logging requests. The OpenID adapter serves a sample waiting room page, similar to the one provided in the sample waiting room stack, but designed for an OpenID authentication flow. The process of becoming authenticated involves getting a position in the waiting room queue and waiting until the serving position is equal or greater than the client’s queue position. The OpenID waiting room page redirects back to the target site, which uses the OpenID API to complete the token acquisition and session configuration for the client. This solution’s API endpoints map directly to the official OpenID Connect 1.0 flow specification, name-for-name. Refer to OpenID Connect Core 1.0 Authentication for details.

AWS Virtual Waiting Room OpenID adaptor component diagram

Virtual Waiting Room on AWS OpenID adaptor component

  1. CloudFront distribution serves the S3 bucket’s content to the user.

  2. S3 bucket hosts sample waiting room pages.

  3. Amazon API Gateway API provides a set of OIDC-compatible APIs that can be used with existing web hosting software that support OIDC identity provider’s Lambda authorize function.

  4. The APIHandler Lambda function handles requests for all API Gateway resource paths. Different Python functions within the same module are mapped to each API path. For example, the /authorize resource path in API Gateway invokes authorize() within the Lambda Function.

  5. OIDC settings are stored in Secrets Manager.

Sample inlet strategies

Inlet strategies determine when the solution's serving counter should move forward to accommodate more users in the target site. For more conceptual information about waiting room inlet strategies, refer to Design considerations.

There are two sample inlet strategies provided by the solution: MaxSize and Periodic.

AWS Virtual Waiting Room Inlet strategies component diagram

Virtual Waiting Room on AWS Inlet strategies component

Max Size inlet strategy option:

  1. A client issues an Amazon SNS notification that invokes the MaxSizeInlet Lambda function to increase the serving counter based on the message payload.

  2. The MaxSizeInlet Lambda function expects to receive a message that it uses it determine how much to increment the serving counter.

Periodic inlet strategy option:

  1. A CloudWatch rule invokes a Lambda function every minute to increase the serving counter by a fixed quantity.

  2. The PeriodicInlet Lambda function increments the serving counter by the given size if the time is between the start and end time provided. Optionally, it checks a CloudWatch alarm and, if the alarm is in OK state, performs the increment, otherwise skips it.

Sample waiting room

The sample waiting room integrates with the public and private APIs in addition to the custom authorizer to demonstrate a minimal end-to-end waiting room solution. The main web page is stored in an S3 bucket and used as an origin to CloudFront. It takes the user through the following steps:

  1. Get in line at the waiting room for entry into the site.

  2. Obtain the client’s position in line.

  3. Obtain the serving position of the waiting room.

  4. Obtain a token set once the serving position is equal or greater to the client’s position.

  5. Use the token to call an API protected by the Lambda authorizer.

Virtual Waiting Room Sample event site component diagram

Virtual Waiting Room on AWS Sample event site component

  1. S3 bucket hosts the sample content for the waiting room and control panel.

  2. CloudFront distribution serves the S3 bucket content to user.

  3. Sample API Gateway deployment with shopping-like resource paths like /search and /checkout. This API is installed by the stack and configured with the token authorizer. It is intended as an example of a simple way to protect an API with the waiting room. Requests that present a valid token are forwarded to the Lambda, otherwise an error is returned. There is no functionality to the API other than the response from the Lambda function attached.