Skip to content

Commit b80a2b8

Browse files
authored
Rate limit group example (#7393)
1 parent f3c7308 commit b80a2b8

File tree

10 files changed

+274
-3
lines changed

10 files changed

+274
-3
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ repos:
66
rev: v5.0.0
77
hooks:
88
- id: trailing-whitespace
9-
exclude: '(\.md|\.snap|\.avdl)$'
9+
exclude: '(\.md|\.jwt|\.snap|\.avdl)$'
1010
- id: end-of-file-fixer
11-
exclude: site/layouts/shortcodes/nic-.*.html
11+
exclude: (site/layouts/shortcodes/nic-.*.html|\.jwt)
1212
- id: check-yaml
1313
args: [--allow-multiple-documents]
1414
exclude: ^(charts/nginx-ingress/templates)

examples/custom-resources/rate-limit-jwt-claim/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ kubectl apply -f webapp.yaml
3030
## Step 2 - Deploy the Rate Limit Policy
3131

3232
In this step, we create a policy with the name `rate-limit-jwt` that allows only 1 request per second coming from a
33-
single IP address.
33+
request containing a JWT claim `sub`.
3434

3535
Create the policy:
3636

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Rate Limit JWT claim
2+
3+
In this example, we deploy a web application, configure load balancing for it via a VirtualServer, and apply two rate
4+
limit Policies, grouped in a tier, using a JWT claim `sub` as the key to the rate limit and using another JWT claim
5+
`user_details.level` to determine which rate limit Policy is applied. One rate limit policy will be the default rate
6+
limit for the group.
7+
8+
## Prerequisites
9+
10+
1. Follow the [installation](https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/)
11+
instructions to deploy the Ingress Controller.
12+
1. Save the public IP address of the Ingress Controller into a shell variable:
13+
14+
```console
15+
IC_IP=XXX.YYY.ZZZ.III
16+
```
17+
18+
1. Save the HTTP port of the Ingress Controller into a shell variable:
19+
20+
```console
21+
IC_HTTP_PORT=<port number>
22+
```
23+
24+
## Step 1 - Deploy a Web Application
25+
26+
Create the application deployments and services:
27+
28+
```console
29+
kubectl apply -f coffee.yaml
30+
```
31+
32+
## Step 2 - Deploy the Rate Limit Policies
33+
34+
In this step, we create two Policies:
35+
36+
- one with the name `rate-limit-jwt-premium`, that allows 10 requests per second coming from a request containing a JWT claim `user_details.level` with a value of `Premium`,
37+
- one with the name `rate-limit-jwt-basic` that allows 1 request per second coming from a request containing a JWT claim `user_details.level` with a value of `Basic`.
38+
39+
The `rate-limit-jwt-basic` Policy is also the default policy if there is not a `user_details.level` JWT claim present.
40+
41+
Create the policies:
42+
43+
```console
44+
kubectl apply -f rate-limit.yaml
45+
```
46+
47+
## Step 3 - Configure Load Balancing
48+
49+
Create a VirtualServer resource for the web application:
50+
51+
```console
52+
kubectl apply -f virtual-server.yaml
53+
```
54+
55+
Note that the VirtualServer references the policies `rate-limit-jwt-premium` & `rate-limit-jwt-basic` created in Step 2.
56+
57+
## Step 4 - Test the Premium Configuration
58+
59+
The Premium JWT payload used in this testing looks like:
60+
61+
```json
62+
{
63+
"user_details": {
64+
"level": "Premium"
65+
},
66+
"sub": "client1",
67+
"name": "John Doe"
68+
}
69+
```
70+
71+
In this test we are relying on the NGINX Plus `ngx_http_auth_jwt_module` to extract the `sub` claim from the JWT payload into the `$jwt_claim_sub` variable and use this as the rate limiting `key`. The NGINX Plus `ngx_http_auth_jwt_module` will also extract the `user_details.level` to select the correct rate limit policy to be applied.
72+
73+
Let's test the configuration. If you access the application at a rate that exceeds 10 requests per second, NGINX will
74+
start rejecting your requests:
75+
76+
```console
77+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat premium-token.jwt`"
78+
```
79+
80+
```text
81+
Server address: 10.8.1.19:8080
82+
Server name: coffee-dc88fc766-zr7f8
83+
. . .
84+
```
85+
86+
```console
87+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat premium-token.jwt`"
88+
```
89+
90+
```text
91+
<html>
92+
<head><title>503 Service Temporarily Unavailable</title></head>
93+
<body>
94+
<center><h1>503 Service Temporarily Unavailable</h1></center>
95+
</body>
96+
</html>
97+
```
98+
99+
> Note: The command result is truncated for the clarity of the example.
100+
101+
## Step 5 - Test the Basic Configuration
102+
103+
The Basic JWT payload used in this testing looks like:
104+
105+
```json
106+
{
107+
"user_details": {
108+
"level": "Basic"
109+
},
110+
"sub": "client2",
111+
"name": "Jane Doe"
112+
}
113+
```
114+
115+
This test is similar to Step 4, however, this time we will be setting the `user_details.level` JWT claim to `Basic`.
116+
117+
Let's test the configuration. If you access the application at a rate that exceeds 1 request per second, NGINX will
118+
start rejecting your requests:
119+
120+
```console
121+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat basic-token.jwt`"
122+
```
123+
124+
```text
125+
Server address: 10.8.1.19:8080
126+
Server name: coffee-dc88fc766-zr7f8
127+
. . .
128+
```
129+
130+
```console
131+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat basic-token.jwt`"
132+
```
133+
134+
```text
135+
<html>
136+
<head><title>503 Service Temporarily Unavailable</title></head>
137+
<body>
138+
<center><h1>503 Service Temporarily Unavailable</h1></center>
139+
</body>
140+
</html>
141+
```
142+
143+
> Note: The command result is truncated for the clarity of the example.
144+
145+
## Step 6 - Test the default Configuration
146+
147+
The default JWT payload used in this testing looks like:
148+
149+
```json
150+
{
151+
"sub": "client3",
152+
"name": "Billy Bloggs"
153+
}
154+
```
155+
156+
This test is similar to Step 4 & 5, however, this time we will not be setting the `user_details.level` JWT claim but
157+
will still be seeing the default `rate-limit-jwt-basic` Policy applied.
158+
159+
Let's test the configuration. If you access the application at a rate that exceeds 1 request per second, NGINX will
160+
start rejecting your requests:
161+
162+
```console
163+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat default-token.jwt`"
164+
```
165+
166+
```text
167+
Server address: 10.8.1.19:8080
168+
Server name: coffee-dc88fc766-zr7f8
169+
. . .
170+
```
171+
172+
```console
173+
curl --resolve cafe.example.com:$IC_HTTP_PORT:$IC_IP http://cafe.example.com:$IC_HTTP_PORT/coffee -H "Authorization: Bearer: `cat default-token.jwt`"
174+
```
175+
176+
```text
177+
<html>
178+
<head><title>503 Service Temporarily Unavailable</title></head>
179+
<body>
180+
<center><h1>503 Service Temporarily Unavailable</h1></center>
181+
</body>
182+
</html>
183+
```
184+
185+
> Note: The command result is truncated for the clarity of the example.
186+
---
187+
> Note: This example does not validate the JWT token sent in the request, you should use either of the [`JWT Using Local Kubernetes Secret`](https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#jwt-using-local-kubernetes-secret) or [`JWT Using JWKS From Remote Location`](https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#jwt-using-jwks-from-remote-location) for that purpose.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2RldGFpbHMiOnsibGV2ZWwiOiJCYXNpYyJ9LCJzdWIiOiJjbGllbnQyIiwibmFtZSI6IkphbmUgRG9lIn0.WeylllL0g70FQqtuz9HQh8oI7-1y9Qlx1_LVCZxAGLE
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../common-secrets/cafe-secret-cafe.example.com.yaml
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: k8s.nginx.org/v1
2+
kind: VirtualServer
3+
metadata:
4+
name: cafe
5+
spec:
6+
host: cafe.example.com
7+
tls:
8+
secret: cafe-secret
9+
upstreams:
10+
- name: coffee
11+
service: coffee-svc
12+
port: 80
13+
policies:
14+
- name: rate-limit-jwt-premium
15+
- name: rate-limit-jwt-basic
16+
routes:
17+
- path: /coffee
18+
action:
19+
pass: coffee
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: coffee
5+
spec:
6+
replicas: 1
7+
selector:
8+
matchLabels:
9+
app: coffee
10+
template:
11+
metadata:
12+
labels:
13+
app: coffee
14+
spec:
15+
containers:
16+
- name: coffee
17+
image: nginxdemos/nginx-hello:plain-text
18+
ports:
19+
- containerPort: 8080
20+
---
21+
apiVersion: v1
22+
kind: Service
23+
metadata:
24+
name: coffee-svc
25+
spec:
26+
ports:
27+
- port: 80
28+
targetPort: 8080
29+
protocol: TCP
30+
name: http
31+
selector:
32+
app: coffee
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnQzIiwibmFtZSI6IkJpbGx5IEJsb2dncyJ9.ARozS58-7UN5enKlH1AXt_QC_tuRoLC1I-lTc0UrJFo
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2RldGFpbHMiOnsibGV2ZWwiOiJQcmVtaXVtIn0sInN1YiI6ImNsaWVudDUiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.LxYflVUa01jsoxo4TbC4h5pnqypBamV1XUqKdAGt968
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
apiVersion: k8s.nginx.org/v1
2+
kind: Policy
3+
metadata:
4+
name: rate-limit-jwt-premium
5+
spec:
6+
rateLimit:
7+
rate: 100r/s
8+
key: ${jwt_claim_sub}
9+
zoneSize: 10M
10+
condition:
11+
jwt:
12+
claim: user_details.level
13+
match: Premium
14+
---
15+
apiVersion: k8s.nginx.org/v1
16+
kind: Policy
17+
metadata:
18+
name: rate-limit-jwt-basic
19+
spec:
20+
rateLimit:
21+
rate: 10r/s
22+
key: ${jwt_claim_sub}
23+
zoneSize: 10M
24+
condition:
25+
jwt:
26+
claim: user_details.level
27+
match: Basic
28+
default: true
29+
---

0 commit comments

Comments
 (0)