-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lambda): add AWS Lambda capability and example (#9)
* Add AWS Lambda capability with example * Update year
- Loading branch information
Showing
38 changed files
with
2,339 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,24 +7,38 @@ Exploring the feasability and performance of a JWT blocklist. | |
|
||
## About | ||
|
||
JWT Block is a blocklist & auth proxy service for JWTs, to support immediate termination of access, since access tokens cannot truly be revoked. | ||
JWT Block is a blocklist & forward auth proxy service for JWTs, to support | ||
immediatetermination of access, since access tokens cannot truly be revoked. | ||
|
||
It is a standalone binary that requires a Redis instance to store the blocklist. | ||
|
||
It can be run as a web service or an AWS Lambda authorizer. | ||
|
||
## Installation | ||
|
||
Download the [binary release](https://github.com/DivergentCodes/jwtblock/releases) for your platform, | ||
and place it in the executable path. | ||
### Build From Source | ||
|
||
1. Have a functional Golang development environment. | ||
2. Build and install: `make && make install` | ||
|
||
### Binary Release | ||
|
||
JWT Block is also available as [a Docker image](https://hub.docker.com/r/divergentcodes/jwtblock). | ||
1. Download the [binary release](https://github.com/DivergentCodes/jwtblock/releases) | ||
for your platform | ||
2. Place the `jwtblock` binary in an executable path. | ||
|
||
### Docker | ||
|
||
JWT Block is available as [a Docker image](https://hub.docker.com/r/divergentcodes/jwtblock). | ||
|
||
``` | ||
docker run -it --rm divergentcodes/jwtblock:latest | ||
docker run --rm -it divergentcodes/jwtblock:latest | ||
``` | ||
|
||
|
||
## Usage | ||
|
||
### CLI | ||
|
||
``` | ||
JWT Block is a blocklist & auth proxy service for JWTs, to support immediate termination of access, since access tokens cannot truly be revoked. | ||
|
@@ -38,6 +52,7 @@ Available Commands: | |
flush Empty the blocklist | ||
help Help about any command | ||
list List blocked JWT hashes | ||
openapi Generate OpenAPI specs for jwtblock | ||
serve Serve the web API | ||
status Get status of the blocklist | ||
unblock Unblock a JWT | ||
|
@@ -47,23 +62,120 @@ Flags: | |
--config string config file (default is ./jwtblock.yaml) | ||
--debug Enable debug mode | ||
-h, --help help for jwtblock | ||
--json Use JSON output | ||
--json Use JSON log output | ||
-q, --quiet Quiet CLI output | ||
--redis-dbnum int Redis DB number | ||
--redis-host string Redis host (default "localhost") | ||
--redis-noverify Skip Redis TLS certificate verification | ||
--redis-pass string Redis password | ||
--redis-port int Redis port (default 6379) | ||
--redis-tls Connect to Redis over TLS (default true) | ||
--redis-tls Connect to Redis over TLS | ||
--redis-user string Redis username | ||
--verbose Verbose CLI output | ||
Use "jwtblock [command] --help" for more information about a command. | ||
``` | ||
|
||
## Configuration | ||
### API | ||
|
||
The web service listens on port `4474/tcp` by default. It has two primary | ||
API endpoints, one for adding tokens to the blocklist (e.g. "logout") and | ||
one to check whether a token is in the blocklist. | ||
|
||
- `POST /blocklist/block` | ||
- `GET /blocklist/check` | ||
|
||
Both endpoints parse the token from the `Authorization` header as a | ||
bearer token. No other parameters are needed. | ||
|
||
Start the web service with `jwtblock serve`. | ||
|
||
OpenAPI specs can be generated with `jwtblock openapi`. | ||
|
||
### AWS Lambda | ||
|
||
> [!TIP] | ||
> Check the full [AWS Lambda example](./examples/aws-lambda-authorizer/README.md). | ||
JWT Block can run as an AWS Lambda function that will handle the following events: | ||
- API Gateway AWS Proxy: handle HTTP requests from API Gateway to block a token. | ||
- API Gateway Authorizer: make authentication decisions for API Gateway, similar to "forward auth" proxies. | ||
|
||
There are a few ways to configure JWT Block (in order of precedence): | ||
### Configuration | ||
|
||
There are multiple ways to configure JWT Block (in order of precedence): | ||
- CLI argument flags. | ||
- Environment variables. | ||
- Configuration file. | ||
|
||
## Demo | ||
|
||
> [!TIP] | ||
> The easiest way to try JWT Block is to spin up the [Docker Compose example](./examples/docker-compose/README.md). | ||
Run a Redis instance and then start the web service with the `serve` subcommand. | ||
|
||
```sh | ||
$ docker run -d --rm -p6379:6379 redis:alpine | ||
402f9668087f59fa085f6bcf5f40db441291f74b6399023a17654575d6d1dc95 | ||
|
||
$ jwtblock serve | ||
JWT Block 0.0.1-DEV-SNAPSHOT-c7d8e29 created by Jack Sullivan <[email protected]> | ||
|
||
Serving the jwtblock web API on :4474 | ||
{"level":"info","message":"Serving web API","func":"HandleRequests","host":"","port":4474} | ||
``` | ||
|
||
Send requests to the service to block a token and verify that it is blocked. | ||
|
||
```sh | ||
export JWT="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNzIyNzIyODg4LCJleHAiOjE3MjI3MjY0ODh9.jPZiGRRudxPAku-FBiWHrxyn95Zj01Pm6ZiUw097fcE" | ||
|
||
$ curl -s -X GET http://jwtblock.localhost:4474/blocklist/check \ | ||
-H "Authorization: Bearer $JWT" \ | ||
| jq | ||
{ | ||
"message": "JWT is allowed", | ||
"blocked": false, | ||
"block_ttl_sec": -1, | ||
"block_ttl_str": "", | ||
"error": false | ||
} | ||
|
||
$ curl -s -X POST http://jwtblock.localhost:4474/blocklist/block \ | ||
-H "Authorization: Bearer $JWT" \ | ||
| jq | ||
{ | ||
"message": "Token blocked", | ||
"error": false | ||
} | ||
|
||
$ curl -s -X GET http://jwtblock.localhost:4474/blocklist/check \ | ||
-H "Authorization: Bearer $JWT" \ | ||
| jq | ||
{ | ||
"message": "JWT is blocked", | ||
"blocked": true, | ||
"block_ttl_sec": 3463, | ||
"block_ttl_str": "57m43s", | ||
"error": false | ||
} | ||
``` | ||
|
||
The blocklist can be managed with the CLI. | ||
|
||
```sh | ||
$ jwtblock --quiet status | ||
Blocklist size: 1 | ||
|
||
$ jwtblock --quiet list | ||
{"level":"info","message":"Listed token hashes in the blocklist","size":1} | ||
0: b8a5471d47b724b277d4861db071ae817556655abd9f31ce7cfa8b055cf9e397 | ||
|
||
$ jwtblock --quiet flush | ||
{"level":"info","message":"Flushed the blocklist","count":1,"result":{"message":"OK","count":1,"error":false}} | ||
Flushed 1 tokens from the blocklist | ||
|
||
$ jwtblock --quiet status | ||
Blocklist size: 0 | ||
``` |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Control the AWS Lambda Authorizor example. | ||
|
||
all: build deploy | ||
|
||
build: | ||
cd ../../; GOOS="linux" GOARCH="amd64" bash ./scripts/build.sh | ||
|
||
deploy: | ||
cp "../../dist/jwtblock_linux_amd64_v1/jwtblock" bootstrap | ||
terraform apply | ||
|
||
stop: | ||
echo "not implemented" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# JWT Block Example: AWS Lambda Authorizer | ||
|
||
This example demonstrates using JWT Block as a Lambda authorizer. | ||
It uses Terraform to provision an AWS environment: | ||
- Dedicated VPC and private subnets. | ||
- API Gateway that sends web requests to the Lambda if a custom authorizer approves. | ||
- Lambda function with the JWT Block binary. | ||
- Redis ElastiCache cluster for the blocklist. | ||
|
||
The Lambda function acts as both a web API endpoint (`POST /block`) | ||
and a [request-based](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html#api-gateway-lambda-authorizer-choose) Lambda authorizer for the API Gateway. | ||
|
||
A Lambda authorizer takes the caller's identity as the input and returns | ||
an IAM policy as the output. The API Gateway then evaluates the returned policy to allow or deny the request. | ||
|
||
## Usage | ||
|
||
Set the AWS profile to use as an environment variable and run `make`. | ||
This will build JWT Block, deploy it to AWS via Terraform, and | ||
provision all of the other necessary infrastructure for the example | ||
(e.g. Redis ElastiCache). | ||
|
||
```sh | ||
export AWS_PROFILE=myaccount | ||
make | ||
``` | ||
|
||
|
||
## Resources | ||
|
||
- [Use API Gateway Lambda authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) (Amazon) | ||
- [Control access to HTTP APIs with AWS Lambda authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html) (Amazon) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
########################################################### | ||
# API Gateway (HTTP) | ||
########################################################### | ||
|
||
resource "aws_apigatewayv2_api" "main" { | ||
name = "${var.project_name}-apigw-http" | ||
description = "APIGW v2 (HTTP) for Lambdas" | ||
protocol_type = "HTTP" | ||
|
||
cors_configuration { | ||
allow_origins = [local.ui_origin] | ||
allow_methods = ["GET", "POST", "OPTIONS"] | ||
allow_headers = ["Authorization", "Content-Type"] | ||
max_age = 3600 # Cache duration for preflight requests | ||
} | ||
} | ||
|
||
resource "aws_apigatewayv2_stage" "main" { | ||
api_id = aws_apigatewayv2_api.main.id | ||
name = "main" | ||
auto_deploy = true | ||
} |
Oops, something went wrong.