Skip to content

Commit

Permalink
chore: update tutorials
Browse files Browse the repository at this point in the history
  • Loading branch information
traefiker authored Nov 7, 2024
1 parent a4e6051 commit 66f06ad
Show file tree
Hide file tree
Showing 21 changed files with 293 additions and 29 deletions.
17 changes: 10 additions & 7 deletions WALKTHROUGH.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ helm repo add --force-update traefik https://traefik.github.io/charts
kubectl create namespace traefik
# Install the Helm chart
helm install traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--set ingressClass.enabled=false \
--set ingressRoute.dashboard.enabled=true \
--set ingressRoute.dashboard.matchRule='Host(`dashboard.docker.localhost`)' \
Expand Down Expand Up @@ -238,9 +238,12 @@ curl -su foo:bar http://walkthrough.docker.localhost/basic-auth/weather | jq
credentials can be visible to any observer when using HTTP. It uses hard-coded credentials, potentially giving more authorization
than required for a specific use case.

Nowadays, those issues are addressed when using [JSON Web Tokens (JWT)](https://datatracker.ietf.org/doc/html/rfc7519). A JWT can be cryptographically verified,
detach authentication from user credentials, and has an issue and expiration date. JWT can be used with Traefik Hub API
Gateway, so let's upgrade our setup to Traefik Hub
API keys are a convenient and more secure way to protect endpoints. The API Key can be required in an HTTP header, cookie, or query parameter.

For more advanced use cases, [JSON Web Tokens (JWT)](https://datatracker.ietf.org/doc/html/rfc7519) can be used. A JWT can be cryptographically verified,
it detaches authentication from user credentials and has an issue and expiration date.

API Key and JWT can be used with Traefik Hub API Gateway, so let's upgrade our setup to Traefik Hub.

## Step 2: Upgrade Traefik Proxy to Traefik Hub API Gateway

Expand All @@ -262,12 +265,12 @@ Then, upgrade Traefik Proxy to Traefik Hub using the same Helm chart:

```shell
helm upgrade traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--reuse-values \
--set hub.token=traefik-hub-license \
--set image.registry=ghcr.io \
--set image.repository=traefik/traefik-hub \
--set image.tag=v3.5.1 \
--set image.tag=v3.6.0 \
traefik/traefik
```

Expand Down Expand Up @@ -392,7 +395,7 @@ First, we enable API Management on Traefik Traefik Hub using the same Helm chart

```shell
helm upgrade traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--reuse-values \
--set hub.apimanagement.enabled=true \
traefik/traefik
Expand Down
8 changes: 4 additions & 4 deletions api-gateway/1-getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ Install Traefik Hub API Gateway using Helm:
helm repo add --force-update traefik https://traefik.github.io/charts
# Install the Helm chart
helm install traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--set hub.token=traefik-hub-license \
--set ingressClass.enabled=false \
--set ingressRoute.dashboard.enabled=true \
--set ingressRoute.dashboard.matchRule='Host(`dashboard.docker.localhost`)' \
--set ingressRoute.dashboard.entryPoints={web} \
--set image.registry=ghcr.io \
--set image.repository=traefik/traefik-hub \
--set image.tag=v3.5.1 \
--set image.tag=v3.6.0 \
--set ports.web.nodePort=30000 \
--set ports.websecure.nodePort=30001 \
traefik/traefik
Expand All @@ -112,15 +112,15 @@ kubectl apply --server-side --force-conflicts -k https://github.com/traefik/trae
helm repo update
# Upgrade the Helm chart
helm upgrade traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--set hub.token=traefik-hub-license \
--set ingressClass.enabled=false \
--set ingressRoute.dashboard.enabled=true \
--set ingressRoute.dashboard.matchRule='Host(`dashboard.docker.localhost`)' \
--set ingressRoute.dashboard.entryPoints={web} \
--set image.registry=ghcr.io \
--set image.repository=traefik/traefik-hub \
--set image.tag=v3.5.1 \
--set image.tag=v3.6.0 \
--set ports.web.nodePort=30000 \
--set ports.websecure.nodePort=30001 \
traefik/traefik
Expand Down
8 changes: 4 additions & 4 deletions api-management/1-getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Now, install Traefik Hub with Helm:
helm repo add --force-update traefik https://traefik.github.io/charts
# Install the Helm chart
helm install traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--set hub.token=traefik-hub-license \
--set hub.apimanagement.enabled=true \
--set ingressClass.enabled=false \
Expand All @@ -91,7 +91,7 @@ helm install traefik -n traefik --wait \
--set ingressRoute.dashboard.entryPoints={web} \
--set image.registry=ghcr.io \
--set image.repository=traefik/traefik-hub \
--set image.tag=v3.5.1 \
--set image.tag=v3.6.0 \
--set ports.web.nodePort=30000 \
--set ports.websecure.nodePort=30001 \
traefik/traefik
Expand All @@ -106,7 +106,7 @@ kubectl apply --server-side --force-conflicts -k https://github.com/traefik/trae
helm repo add --force-update traefik https://traefik.github.io/charts
# Upgrade the Helm chart
helm upgrade traefik -n traefik --wait \
--version v32.1.0 \
--version v33.0.0 \
--set hub.token=traefik-hub-license \
--set hub.apimanagement.enabled=true \
--set ingressClass.enabled=false \
Expand All @@ -115,7 +115,7 @@ helm upgrade traefik -n traefik --wait \
--set ingressRoute.dashboard.entryPoints={web} \
--set image.registry=ghcr.io \
--set image.repository=traefik/traefik-hub \
--set image.tag=v3.5.1 \
--set image.tag=v3.6.0 \
--set ports.web.nodePort=30000 \
--set ports.websecure.nodePort=30001 \
traefik/traefik
Expand Down
148 changes: 147 additions & 1 deletion api-management/4-protect-api-infrastructure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ We can see the HTTP header `X-Quota-Remaining: 494` is present, so our new API P
Also, If you haven't yet noticed, despite having 500 requests in our new quota, the header says the quota remaining is `494`.
This means that when we applied the new API plan, the system took account of our previously exhausted 5 requests.

### Viewing your API plan in Traefik Hub online dashboard
### Viewing your API plan in the Traefik Hub online dashboard

With our API plans and API Accesses created, if we navigate to the [Traefik Hub Online Dashboard](https://hub.traefik.io/plans), we should see the new API plans listed.

Expand All @@ -408,7 +408,153 @@ If you click on **Multiple plans applied**, you should see all the plans we have

!["Multiple plans applied"](./images/multiple-plans-applied.png)

## Utilize API bundles to manage multiple APIs

In this section, We’ll create an [API Bundle](https://doc.traefik.io/traefik-hub/api-management/api-bundle) that includes the weather API and a new API called `whoami`.
This bundle will allow us to apply API Plans collectively to the APIs, facilitating easier management.

First, we need to deploy all the resources needed for the `whoami` app:

```sh
kubectl apply -f src/manifests/whoami-app.yaml
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/whoami-ingressroute.yaml
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/whoami-api.yaml
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/whoami-apiaccess.yaml
```

After this has been deployed, if we make a request to `whoami` using the external token, we should get a response:

```sh
curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/whoami"
```

```sh
HTTP/1.1 200 OK
Content-Length: 691
Content-Type: text/plain; charset=utf-8
```

Now, let's create an API Bundle in the apps namespace for both APIs:

```yaml :manifests/api-bundle.yaml
apiVersion: hub.traefik.io/v1alpha1
kind: APIBundle
metadata:
name: protect-api-infrastructure-apimanagement-bundle
namespace: apps
spec:
apis:
- name: protect-api-infrastructure-apimanagement-admin
- name: protect-api-infrastructure-apimanagement-whoami
```

And apply it:

```sh
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/api-bundle.yaml
```

>[!NOTE]
> API Bundles cannot include other API Bundles to maintain clear and manageable hierarchies.

Let's create an API plan for the bundle:

```yaml :manifests/apiplan-for-bundle.yaml
apiVersion: hub.traefik.io/v1alpha1
kind: APIPlan
metadata:
name: plan-for-bundle
namespace: apps
spec:
title: "Weather & Whoami Bundle Plan"
description: "Enforces rate limits and quotas for both the Weather and Whoami APIs"
rateLimit:
limit: 1
period: 1s
quota:
limit: 500
period: 24h
```

```sh
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/api-plan-for-bundle.yaml
```

Now, let's link it with an API Access that allows only the `external` group to have access to both APIs:

```yaml :manifests/api-bundle-access.yaml
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
name: protect-api-infrastructure-apimanagement-external-bundle
namespace: apps
spec:
groups:
- external
apiBundles:
- name: protect-api-infrastructure-apimanagement-bundle
apiPlan:
name: plan-for-bundle
weight: 5 # Higher weight to prioritize this plan over previous APIAccess resources
```

Apply the new API access:

```sh
kubectl apply -f api-management/4-protect-api-infrastructure/manifests/api-bundle-access.yaml
```

Now, Let's test the bundle.

If we make a request to the whoami API, we should get a response:

```sh
curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/whoami"
```

```sh
HTTP/1.1 200 OK
Content-Length: 691
Content-Type: text/plain; charset=utf-8
Date: Thu, 17 Oct 2024 07:01:35 GMT
X-Quota-Remaining: 499
X-Ratelimit-Remaining: 0
```

As you can see, we get both the `X-Quota-Remaining` and `X-Ratelimit-remaining` headers because of our API plan for the bundle.

Now, if we make a request to the weather API:

```sh
curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
```

We should also get a response from the API:

```sh
HTTP/1.1 200 OK
Content-Length: 163
Content-Type: text/plain; charset=utf-8
Date: Thu, 17 Oct 2024 07:18:02 GMT
X-Quota-Remaining: 498
X-Ratelimit-Remaining: 0
```

If you haven't noticed, the APIs' rate limit and quota are handled as one because they are referenced in the same API Access as part of a bundle.So this means, if we exhaust the quota on the weather API,
it will also affect the whoami API.

### Viewing your API bundle in the Traefik Hub online dashboard

With our API bundle created, if we navigate to the [Traefik Hub Online Dashboard](https://hub.traefik.io/bundles), we should see the new API bundle and all the APIs in the bundle listed.

!["API bundle page in Traefik Hub Online Dashboard"](./images/api-bundle.png)

Also, if we navigate to the Apps API Portal we deployed earlier in the [getting started tutorial](../1-getting-started/README.md#step-5-deploy-the-api-portal), we should see the APIs listed as part of a bundle.

!["API page in the Apps API portal"](./images/api-portal-bundle.png)

And that's it! In this tutorial, we've:

- Secured access to our exposed APIs by defining access policies using `APIAccess` resources.
- Protected our APIs from excessive usage by implementing rate limits and quotas through `APIPlan` resources.
- Utilized `APIBundle` to manage multiple APIs collectively and apply API Plans efficiently.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
name: protect-api-infrastructure-apimanagement-external-bundle
namespace: apps
spec:
groups:
- external
apiBundles:
- name: protect-api-infrastructure-apimanagement-bundle
apiPlan:
name: plan-for-bundle
weight: 1 # Higher weight to prioritize this plan over previous APIAccess resources
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: hub.traefik.io/v1alpha1
kind: APIBundle
metadata:
name: protect-api-infrastructure-apimanagement-bundle
namespace: apps
spec:
apis:
- name: protect-api-infrastructure-apimanagement-weather
- name: protect-api-infrastructure-apimanagement-whoami
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: hub.traefik.io/v1alpha1
kind: APIPlan
metadata:
name: plan-for-bundle
namespace: apps
spec:
title: "Weather & whoami Bundle Plan"
description: "Enforces rate limits and quotas for both the Weather and Whoami APIs"
rateLimit:
limit: 1
period: 1s
quota:
limit: 500
period: 24h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: hub.traefik.io/v1alpha1
kind: API
metadata:
name: protect-api-infrastructure-apimanagement-whoami
namespace: apps
spec: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: hub.traefik.io/v1alpha1
kind: APIAccess
metadata:
name: protect-api-infrastructure-apimanagement-whoami
namespace: apps
spec:
groups:
- external
apis:
- name: protect-api-infrastructure-apimanagement-whoami
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: protect-api-infrastructure-apimanagement-whoami
namespace: apps
annotations:
hub.traefik.io/api: protect-api-infrastructure-apimanagement-whoami
spec:
entryPoints:
- web
routes:
- match: Host(`api.protect-infrastructure.apimanagement.docker.localhost`) && PathPrefix(`/whoami`)
kind: Rule
services:
- name: whoami
port: 80
2 changes: 1 addition & 1 deletion src/api-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.10
# syntax=docker/dockerfile:1.11

# golang builder
FROM golang:1.23 AS builder
Expand Down
2 changes: 1 addition & 1 deletion src/manifests/admin-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ spec:
spec:
containers:
- name: api
image: ghcr.io/traefik/api-server:v1.0.0
image: ghcr.io/traefik/api-server:v1.1.0
args: ["-data", "/api/api.json", "-errorrate", "2"]
imagePullPolicy: IfNotPresent
volumeMounts:
Expand Down
2 changes: 1 addition & 1 deletion src/manifests/weather-app-forecast.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ spec:
spec:
containers:
- name: api
image: ghcr.io/traefik/api-server:v1.0.0
image: ghcr.io/traefik/api-server:v1.1.0
args: ["-data", "/api/api.json", "-errorrate", "2"]
imagePullPolicy: IfNotPresent
volumeMounts:
Expand Down
2 changes: 1 addition & 1 deletion src/manifests/weather-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ spec:
spec:
containers:
- name: api
image: ghcr.io/traefik/api-server:v1.0.0
image: ghcr.io/traefik/api-server:v1.1.0
args: ["-data", "/api/api.json", "-openapi", "/public/openapi.yaml", "-errorrate", "2"]
imagePullPolicy: IfNotPresent
volumeMounts:
Expand Down
Loading

0 comments on commit 66f06ad

Please sign in to comment.