|
1 |
| -# Protecting an API with JSON Web Tokens (JWTs) and Kubernetes authnz using Kuadrant |
| 1 | +# Rate-limiting and protecting an API with JSON Web Tokens (JWTs) and Kubernetes authnz using Kuadrant |
2 | 2 |
|
3 |
| -Example of protecting an API (the Toy Store API) with authentication based on ID tokens (signed JWTs) issued by an |
4 |
| -OpenId Connect (OIDC) server (Keycloak) and alternative Kubernetes Service Account tokens, and authorization based on |
5 |
| -Kubernetes RBAC, with permissions (bindings) stored as Kubernetes Roles and RoleBindings. |
| 3 | +Example of rate-limiting and protecting an API (the Toy Store API) with authentication based on ID tokens (signed JWTs) |
| 4 | +issued by an OpenId Connect (OIDC) server (Keycloak) and alternative Kubernetes Service Account tokens, and authorization |
| 5 | +based on Kubernetes RBAC, with permissions (bindings) stored as Kubernetes Roles and RoleBindings. |
6 | 6 |
|
7 | 7 | ## Pre-requisites
|
8 | 8 |
|
9 | 9 | - [Docker](https://www.docker.com/)
|
10 | 10 | - [kubectl](https://kubernetes.io/docs/reference/kubectl/) command-line tool
|
11 | 11 | - [jq](https://stedolan.github.io/jq/)
|
12 | 12 |
|
13 |
| -## Run the guide ❶ → ❻ |
| 13 | +## Run the guide ❶ → ❼ |
14 | 14 |
|
15 | 15 | ### ❶ Setup the environment
|
16 | 16 |
|
@@ -124,6 +124,15 @@ spec:
|
124 | 124 | user:
|
125 | 125 | valueFrom:
|
126 | 126 | authJSON: auth.identity.sub
|
| 127 | + response: |
| 128 | + - name: rate-limit |
| 129 | + json: |
| 130 | + properties: |
| 131 | + - name: userID |
| 132 | + valueFrom: |
| 133 | + authJSON: auth.identity.sub |
| 134 | + wrapper: envoyDynamicMetadata |
| 135 | + wrapperKey: ext_auth_data |
127 | 136 | EOF
|
128 | 137 | ```
|
129 | 138 |
|
@@ -270,6 +279,61 @@ curl -H "Authorization: Bearer $SA_TOKEN" -H 'Host: api.toystore.com' -X POST ht
|
270 | 279 | # HTTP/1.1 403 Forbidden
|
271 | 280 | ```
|
272 | 281 |
|
| 282 | +### ❼ Create the `RateLimitPolicy` |
| 283 | + |
| 284 | +```sh |
| 285 | +kubectl apply -f -<<EOF |
| 286 | +apiVersion: kuadrant.io/v1beta1 |
| 287 | +kind: RateLimitPolicy |
| 288 | +metadata: |
| 289 | + name: toystore-rate-limit |
| 290 | +spec: |
| 291 | + targetRef: |
| 292 | + group: gateway.networking.k8s.io |
| 293 | + kind: HTTPRoute |
| 294 | + name: toystore |
| 295 | + rateLimits: |
| 296 | + - configurations: |
| 297 | + - actions: |
| 298 | + - metadata: |
| 299 | + descriptor_key: "userID" |
| 300 | + default_value: "no-user" |
| 301 | + metadata_key: |
| 302 | + key: "envoy.filters.http.ext_authz" |
| 303 | + path: |
| 304 | + - segment: |
| 305 | + key: "ext_auth_data" |
| 306 | + - segment: |
| 307 | + key: "userID" |
| 308 | + limits: |
| 309 | + - conditions: [] |
| 310 | + maxValue: 5 |
| 311 | + seconds: 10 |
| 312 | + variables: |
| 313 | + - userID |
| 314 | +EOF |
| 315 | +``` |
| 316 | + |
| 317 | +> **Note:** It may take a couple minutes for the RateLimitPolicy to be applied depending on your cluster. |
| 318 | +
|
| 319 | +#### Try the API rate limited |
| 320 | + |
| 321 | +Send requests as the Keycloak-authenticated user: |
| 322 | + |
| 323 | +```sh |
| 324 | +while :; do curl --write-out '%{http_code}' --silent --output /dev/null -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Host: api.toystore.com' http://localhost:9080/toy | egrep --color "\b(429)\b|$"; sleep 1; done |
| 325 | +``` |
| 326 | + |
| 327 | +Send requests as the service account: |
| 328 | + |
| 329 | +```sh |
| 330 | +while :; do curl --write-out '%{http_code}' --silent --output /dev/null -H "Authorization: Bearer $SA_TOKEN" -H 'Host: api.toystore.com' http://localhost:9080/toy | egrep --color "\b(429)\b|$"; sleep 1; done |
| 331 | +``` |
| 332 | + |
| 333 | +Each user should be entitled to a maximum of 5 requests to the API every 10 seconds. |
| 334 | + |
| 335 | +> **Note:** You may need to refresh the tokens if they are expired. |
| 336 | +
|
273 | 337 | ## Cleanup
|
274 | 338 |
|
275 | 339 | ```sh
|
|
0 commit comments