Lightweight HTTP API Gateway.
The gateway will perform proxying, rate limiting and token validation based on the rules defined in the configuration file.
- Dependencies (for development)
- Quick start
- Development
- HTTP Request
- Trigger Rate Limiting
- HTTP Response Status Codes
- Configuration
- Artifacts
- Credits
- TODO
- Make
- Docker
- Docker Compose
- HTTPie
Start proxy
make dev
Make HTTP request
http :8080/health
Any changes made to the go or yml files will result in the application being recompiled and relaunched
make dev
Just like make dev
, the below command will rerun tests if any changes are made to either go or yml files
make dev-test
/gateway/health
...
...
Just like make dev
, the below will automatically recompiled and relaunched the application, but targeting a Kubernetes
cluster.
skaffold dev
Perform a http request using HTTPie
http :8080
seq 10 | xargs -P 4 -I '{}' http post :8080/health
The following status codes could be returned by the gateway but could also originate from the server which the request was proxied to
Code | Meaning | Reason |
---|---|---|
403 | Forbidden | Invalid token |
421 | Misdirected Request | No matching rule found |
429 | Too Many Requests | Rate limits exceeded |
The following configuration will proxy all get requests to /health, to the defaultBackend
.
All other requests will be rate limited before being proxied to the same backend.
serverPort: 8080
defaultBackend: backend
backends:
- name: backend
url: http://backend:8080
rules:
- pathPrefix: /health
method: GET
- pathPrefix: /
requestPerSecond: 2
burst: 2
It's possible to define a base path property. The value of such will be prepended to all path prefixes.
basePath: /test
rules:
- pathPrefix: /health
The above configuration will match the incoming request against the path prefix /test/health
.
Access to certain paths can be blocked by using the block
property of a rule
rules:
- pathPrefix: /prefix
block: true
Multiple backends might serve content from the same paths. To accommodate this use case a URL can be rewritten by replacing part of its path.
- pathPrefix: /something
pathReplace:
target: thing
replacement: body
The above rule would rewrite the incoming request path to /somebody
The replacement
key is optional and defaults to an empty string.
- pathPrefix: /something
pathReplace:
target: thing
The above rule would rewrite the incoming request path to /some
Rate limiting is done per rule basis by defining the number of requests which are allowed per second and how much burst to allowed.
rules:
- pathPrefix: /
requestPerSecond: 2
burst: 2
This is implemented using tollbooth.
Token validation is supported via public key validation.
NOTE: The
jwks
andjwt
configurations are mutually exclusive and if both are defined thejwks
configuration is evaluated first and takes precedence.
A public key can be retrieved from a remote JWKS if a configuration like the below is specified
authentication:
jwks:
host: http://jwks/jwks.json
index: 0
minimumRefreshInterval: 960 # 15 minutes
A static public key can be configured as shown below.
authentication:
jwt:
publicKey: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtYrBsSkVGXZKQL13lbmd
xFCQcvi6KIssjz3KOHIko/Da6sxE2w67OL84t98wCYbmIuq6xTK6qpEqEs1LaqQS
DnCs2VNDTLk4D1J42R63OpJQfOfebzhTJLx6KldyK2FRGXWILY7AzcoqyuLk433s
lHk6/yFDYgBA4COofeXZvXtUazuzpBWTZCxpEh341ob6XQ5juLYrqr/80XLYzXiu
N1iz24ulxSnD0GV4cRfHEnnzN3oYFzoYTcTQB6dffNAs/ADHNA9IemyLbT0ugvbf
L5MOEBOftYLRwmGFWrXf5s9jccku0FPid2wtZEwsv5Sa+Yvr36KHtrr+PSFksOB1
0QIDAQAB
-----END PUBLIC KEY-----
The incoming request needs to specify a token in the HTTP authorization header.
It can be either as
Authorization: token
Or prefixed with the string "Bearer"
Authorization: Bearer token
An example of an authorizing request can be seen below
export ACCESS_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQ3OTExNTQ0MTUsImlhdCI6MTYzNzU1NDQxNX0.PtQp6_k5bQ9KE9uk520i4emVnUmxFD8DxyeZsfzgT6CY2oMyXEm7zlIA-4_xz2Q7CrSeqnWxpy0coK9MN0EPE2vhFomTrP6D3l7_lX6Dyn1gH6zWpjC_dRqOSRv3AqS3buZiC-vNwCatLhu6WE74cykBAE2veIr8Gp_ebiITXJKiHBNaTlPk2WEfcJ1NL3g7nafy6l-V4h2-Vj3tapJQiLfpgReIXYIswFYH7En7qy94fL0eOUbZzQI9fOuiXvAN-owR3GYcbwz9Hll23VACWsekMJdDBEgUSdek9JOmRHGxko6FE79-_ClYvF1dGUgZB2mDwY_xF2TOG2q3XDi9Aw
http get :8080/ "Authorization: Bearer $ACCESS_TOKEN"
The following environment variables are support and will take precedence over values defined in the configuration file.
Variable | Configuration path |
---|---|
APIG_SERVER_PORT | serverPort |
APIG_BASE_PATH | basePath |
APIG_DEFAULT_BACKEND | defaultBackend |
APIG_PUBLIC_KEY | authentication.jwt.publicKey |
A request will first be matched by HTTP method and path prefix. If a match is found HTTP headers will be evaluated.
- pathPrefix: /health
method: GET
headers:
User-Agent:
- HTTPie/2.6.0
The pathPrefix property is the only mandatory rule property
A rule as simple as the following will match all incoming requests with a path starting with /health
- pathPrefix: /health
The below rule serves as a catch-all rule
- pathPrefix: / # catch all
A catch-all rule supports the normal HTTP method and http header matching properties. If any of such are defined it'll * only* catch requests matching those criteria.
A tree entry will be created for each HTTP method and the path prefix configured. The entry will be a concatenation of the HTTP method and the path prefix.
method+pathPrefix
If the method property isn't defined, an entry for each of the following methods will be created.
- GET
- HEAD
- POST
- PUT
- PATCH
- DELETE
- CONNECT
- OPTIONS
- TRACE
It's therefore considered best practice to specify the HTTP method on a rule if possible.
Requests can be matched against an exact hostname as seen below.
- pathPrefix: /
hostname: domain.org
If the hostname is prefixed with a "*". Any subdomain of domain.org
will match the below rule.
- pathPrefix: /
hostname: "*.domain.org"
NOTE: The "*" is considered a wildcard for subdomains only and can only be used as a prefix. The following will not work
doma*.org
.
- pathPrefix: /
headers:
User-Agent:
- HTTPie/2.6.0
The following artifact can be produced by invoking make targets
make binary
The docker image can be created using the below command
make docker-image
The below command will push the image to the registry defined under the prod
service in the docker compose file.
make push-docker-image
The helm chart can be packed using the below command
make helm-chart
The below command will publish the chart
make publish-helm
NOTE: The environment variables
CHART_AUTH_USER
andCHART_AUTH_PASS
needs to contain valid credentials
- https://github.com/lestrrat-go/jwx
- https://github.com/hashicorp/go-immutable-radix
- https://github.com/didip/tollbooth
- Comment exported types and functions
- Config validation
-
- If publicKey == nil && c.Rules... wants to authenticate... complain
-
- If config.DefaultBackend == nil && c.Rules... has no backend... complain
-
- Identical rules
- Don't return 502 when the backend isn't found 2022/01/04 01:54:11 http: proxy error: dial tcp: lookup im-job-dev.instance-manager-dev.svc on 172.20.0.10:53: no such host