diff --git a/README.md b/README.md
index b67f620..80c7e83 100644
--- a/README.md
+++ b/README.md
@@ -48,13 +48,11 @@ The journey can start [here](WALKTHROUGH.md) for a quickstart with a global over
```shell
.
├── api-gateway # Traefik Hub API Gateway tutorials
-│ ├── 1-getting-started
-│ ├── 2-secure-applications
+│ ├── 1-getting-started # API Gateway Quick Start Guide
+│ ├── 2-expose
+│ ├── 3-secure-applications
├── api-management # Traefik Hub API Management tutorials
-│ ├── 1-getting-started
-│ ├── 2-access-control
-│ ├── 3-api-lifecycle-management
-│ └── 4-protect-api-infrastructure (WIP)
+│ ├── 1-getting-started # API Management Quick Start Guide
└── src
├── api-server # API server source code
└── manifests # Yaml to deploy all apps
diff --git a/WALKTHROUGH.md b/WALKTHROUGH.md
deleted file mode 100644
index 58c5864..0000000
--- a/WALKTHROUGH.md
+++ /dev/null
@@ -1,626 +0,0 @@
-# Walkthrough
-
-This document covers a complete journey: Traefik Proxy => Traefik Hub API Gateway => Traefik Hub API Management
-
-## Deploy Kubernetes
-
-For this tutorial, we deploy Traefik Hub API Gateway on a [k3d](https://k3d.io/) cluster. It's possible to use alternatives such as [kind](https://kind.sigs.k8s.io), cloud providers, and others.
-
-First, clone the GitHub repository dedicated to tutorials:
-
-```shell
-git clone https://github.com/traefik/hub.git
-cd hub
-```
-
-### Using k3d
-
-```shell
-k3d cluster create traefik-hub --port 80:80@loadbalancer --port 443:443@loadbalancer --port 8000:8000@loadbalancer --k3s-arg "--disable=traefik@server:0"
-```
-
-### Using Kind
-
-kind requires some configuration to use an IngressController on localhost. See the following example:
-
-
-
-Create the cluster
-
-Ports need to be mapped for HTTP and HTTPS for kind with this config:
-
-```yaml
-kind: Cluster
-apiVersion: kind.x-k8s.io/v1alpha4
-name: traefik-hub
-nodes:
-- role: control-plane
- extraPortMappings:
- - containerPort: 30000
- hostPort: 80
- protocol: TCP
- - containerPort: 30001
- hostPort: 443
- protocol: TCP
-```
-
-```shell
-kind create cluster --config=src/kind/config.yaml
-kubectl cluster-info
-kubectl wait --for=condition=ready nodes traefik-hub-control-plane
-```
-
-And add a load balancer (LB) to it:
-
-```shell
-kubectl apply -f src/kind/metallb-native.yaml
-kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=90s
-kubectl apply -f src/kind/metallb-config.yaml
-```
-
-
-
-## Step 1: Deploy an API with Traefik Proxy
-
-First, we will install Traefik Proxy with Helm:
-
-```shell
-# Add the Helm repository
-helm repo add --force-update traefik https://traefik.github.io/charts
-# Create a namespace
-kubectl create namespace traefik
-# Install the Helm chart
-helm install traefik -n traefik --wait \
- --version v34.4.1 \
- --set ingressClass.enabled=false \
- --set ingressRoute.dashboard.enabled=true \
- --set ingressRoute.dashboard.matchRule='Host(`dashboard.docker.localhost`)' \
- --set ingressRoute.dashboard.entryPoints={web} \
- --set ports.web.nodePort=30000 \
- --set ports.websecure.nodePort=30001 \
- traefik/traefik
-```
-
-Once it's installed, we can access the local dashboard: http://dashboard.docker.localhost/
-
-
-
-Without Traefik Hub, an API can be deployed with an `Ingress`, an `IngressRoute` or a `HTTPRoute`.
-
-This tutorial implements APIs using a JSON server in Go; the source code is [here](../../src/api-server/).
-
-Let's deploy a [weather app](../../src/manifests/weather-app.yaml) exposing an API.
-
-```shell
-kubectl apply -f src/manifests/apps-namespace.yaml
-kubectl apply -f src/manifests/weather-app.yaml
-```
-
-It should create the public app:
-
-```shell
-namespace/apps created
-configmap/weather-data created
-deployment.apps/weather-app created
-service/weather-app created
-```
-
-It can be exposed with an `IngressRoute`:
-
-```yaml :src/manifests/walkthrough/weather-app-no-auth.yaml
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: walkthrough-weather-api-no-auth
- namespace: apps
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`walkthrough.docker.localhost`) && PathPrefix(`/no-auth`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
-```
-
-```shell
-kubectl apply -f src/manifests/walkthrough/weather-app-no-auth.yaml
-```
-
-```shell
-ingressroute.traefik.io/walkthrough-weather-api created
-```
-
-This API can be accessed using curl:
-
-```shell
-curl -s http://walkthrough.docker.localhost/no-auth/weather | jq
-```
-
-```json
-[
- {"city":"GopherTown","id":"0","weather":"Cloudy"},
- {"city":"City of Gophers","id":"1","weather":"Sunny"},
- {"city":"GopherRocks","id":"2","weather":"Cloudy"}
-]
-```
-
-With Traefik Proxy, we can secure the access to this API using the Basic Authentication. To create an encoded _user_:_password_ pair, we can use `htpasswd` with `openssl` to encode it.
-
-So let's do it:
-
-```shell
-htpasswd -nb foo bar | openssl base64
-```
-
-```shell
-Zm9vOiRhcHIxJDJHR0RyLjJPJDdUVXJlOEt6anQ1WFFOUGRoby5CQjEKCg==
-```
-
-```diff :hack/diff.sh -r -a "-Nau src/manifests/walkthrough/weather-app-no-auth.yaml src/manifests/walkthrough/weather-app-basic-auth.yaml"
---- src/manifests/walkthrough/weather-app-no-auth.yaml
-+++ src/manifests/walkthrough/weather-app-basic-auth.yaml
-@@ -1,17 +1,38 @@
- ---
-+apiVersion: v1
-+kind: Secret
-+metadata:
-+ name: basic-auth
-+ namespace: apps
-+data:
-+ users: |
-+ Zm9vOiRhcHIxJDJHR0RyLjJPJDdUVXJlOEt6anQ1WFFOUGRoby5CQjEKCg==
-+
-+---
-+apiVersion: traefik.io/v1alpha1
-+kind: Middleware
-+metadata:
-+ name: basic-auth
-+ namespace: apps
-+spec:
-+ basicAuth:
-+ secret: basic-auth
-+
-+---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: walkthrough-weather-api-no-auth
-+ name: walkthrough-weather-api-basic-auth
- namespace: apps
- spec:
- entryPoints:
- - web
- routes:
-- - match: Host(`walkthrough.docker.localhost`) && PathPrefix(`/no-auth`)
-- kind: Rule
-- services:
-- - name: weather-app
-- port: 3000
-- middlewares:
-- - name: stripprefix-weather
-+ - match: Host(`walkthrough.docker.localhost`) && PathPrefix(`/basic-auth`)
-+ kind: Rule
-+ services:
-+ - name: weather-app
-+ port: 3000
-+ middlewares:
-+ - name: stripprefix-weather
-+ - name: basic-auth
-```
-
-Let's apply it:
-
-```shell
-kubectl apply -f src/manifests/walkthrough/weather-app-basic-auth.yaml
-```
-
-```shell
-secret/basic-auth created
-middleware.traefik.io/basic-auth created
-ingressroute.traefik.io/walkthrough-weather-api-basic-auth created
-```
-
-And now, we can confirm it's secured using BASIC Authentication :
-
-```shell
-# This call is not authorized => 401
-curl -i http://walkthrough.docker.localhost/basic-auth/weather
-# This call is allowed => 200
-curl -su foo:bar http://walkthrough.docker.localhost/basic-auth/weather | jq
-```
-
-[Basic Authentication](https://datatracker.ietf.org/doc/html/rfc7617) worked and was widely used in the early days of the web. However, it also has a security risk:
-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.
-
-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
-
-Log in to the [Traefik Hub Online Dashboard](https://hub.traefik.io), open the page to [generate a new Hub API Gateway](https://hub.traefik.io/gateways/new).
-
-**:warning: Do not install the Hub API Gateway, but copy the token.**
-
-Now, open a terminal and run these commands to create the secret for Traefik Hub.
-
-```shell
-export TRAEFIK_HUB_TOKEN=
-```
-
-```shell
-kubectl create secret generic traefik-hub-license --namespace traefik --from-literal=token=$TRAEFIK_HUB_TOKEN
-```
-
-Then, upgrade Traefik Proxy to Traefik Hub using the same Helm chart:
-
-```shell
-helm upgrade traefik -n traefik --wait \
- --version v34.4.1 \
- --reuse-values \
- --set hub.token=traefik-hub-license \
- --set image.registry=ghcr.io \
- --set image.repository=traefik/traefik-hub \
- --set image.tag=v3.14.1 \
- traefik/traefik
-```
-
-Traefik Hub is 100% compatible with Traefik Proxy v3.
-
-The dashboard is still reachable (http://dashboard.docker.localhost/). One can notice now the Traefik Hub API Gateway logo on the top left corner.
-
-
-
-And also confirm _Basic Auth_ is still here:
-
-```shell
-# This call is not authorized => 401
-curl -i http://walkthrough.docker.localhost/basic-auth/weather
-# This call is allowed => 200
-curl -su foo:bar http://walkthrough.docker.localhost/basic-auth/weather | jq
-```
-
-Let's secure the weather API with an API Key.
-
-With Traefik Hub, we can use API Key as a middleware. First, we'll need to generate hash of our password. It can be done with `htpasswd` :
-
-```shell
-htpasswd -nbs "" "Let's use API Key with Traefik Hub" | cut -c 2-
-{SHA}dhiZGvSW60OMQ+J6hPEyJ+jfUoU=
-```
-
-```shell
-{SHA}dhiZGvSW60OMQ+J6hPEyJ+jfUoU=
-```
-
-We can now put this password in the API Key middleware:
-
-```diff :hack/diff.sh -r -a "-Nau src/manifests/walkthrough/weather-app-no-auth.yaml src/manifests/walkthrough/weather-app-apikey.yaml"
---- src/manifests/walkthrough/weather-app-no-auth.yaml
-+++ src/manifests/walkthrough/weather-app-apikey.yaml
-@@ -1,17 +1,42 @@
- ---
-+apiVersion: v1
-+kind: Secret
-+metadata:
-+ name: walkthrough-apikey-auth
-+ namespace: apps
-+stringData:
-+ secretKey: "{SHA}dhiZGvSW60OMQ+J6hPEyJ+jfUoU="
-+
-+---
-+apiVersion: traefik.io/v1alpha1
-+kind: Middleware
-+metadata:
-+ name: walkthrough-apikey-auth
-+ namespace: apps
-+spec:
-+ plugin:
-+ apiKey:
-+ keySource:
-+ header: Authorization
-+ headerAuthScheme: Bearer
-+ secretValues:
-+ - urn:k8s:secret:walkthrough-apikey-auth:secretKey
-+
-+---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: walkthrough-weather-api-no-auth
-+ name: walkthrough-weather-api-api-key
- namespace: apps
- spec:
- entryPoints:
- - web
- routes:
-- - match: Host(`walkthrough.docker.localhost`) && PathPrefix(`/no-auth`)
-- kind: Rule
-- services:
-- - name: weather-app
-- port: 3000
-- middlewares:
-- - name: stripprefix-weather
-+ - match: Host(`walkthrough.docker.localhost`) && PathPrefix(`/api-key`)
-+ kind: Rule
-+ services:
-+ - name: weather-app
-+ port: 3000
-+ middlewares:
-+ - name: stripprefix-weather
-+ - name: walkthrough-apikey-auth
-```
-
-Let's apply it:
-
-```shell
-kubectl apply -f src/manifests/walkthrough/weather-app-apikey.yaml
-```
-
-```shell
-secret/walkthrough-apikey-auth created
-middleware.traefik.io/walkthrough-apikey-auth created
-ingressroute.traefik.io/walkthrough-weather-api-api-key created
-```
-
-And test it:
-
-```shell
-# This call is not authorized => 401
-curl -i http://walkthrough.docker.localhost/api-key/weather
-# Let's set the token
-export API_KEY=$(echo -n "Let's use API Key with Traefik Hub" | base64)
-# This call with the token is allowed => 200
-curl -s -H "Authorization: Bearer $API_KEY" http://walkthrough.docker.localhost/api-key/weather | jq
-```
-
-The API is now secured.
-
-It's possible to handle users with an Identity Provider, but what if we want to cover _internal_ and _external_ use cases? To protect API on HTTP _verb_ level? Or to test a new version with part of the production traffic?
-
-We'll need Traefik Hub with API Management!
-
-## Step 3: Manage an API with Traefik Hub API Management
-
-First, we enable API Management on Traefik Traefik Hub using the same Helm chart:
-
-```shell
-helm upgrade traefik -n traefik --wait \
- --version v34.4.1 \
- --reuse-values \
- --set hub.apimanagement.enabled=true \
- traefik/traefik
-```
-
-Traefik Hub API Management is 100% compatible with Traefik Proxy v3 and Traefik Hub API Gateway.
-
-The dashboard is still reachable on http://dashboard.docker.localhost/
-
-
-
-And also confirm that the API is still secured using an API Key:
-
-```shell
-# This call is not authorized => 401
-curl -i http://walkthrough.docker.localhost/api-key/weather
-# This call with the token is allowed => 200
-curl -s -H "Authorization: Bearer $API_KEY" http://walkthrough.docker.localhost/api-key/weather | jq
-```
-
-Now, let's try to manage it with Traefik Hub using `API` and `APIAccess` resources:
-
-```yaml :src/manifests/walkthrough/api.yaml -s 1 -e 23
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: walkthrough-weather-api
- namespace: apps
-spec:
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
- - url: http://api.walkthrough.docker.localhost
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: walkthrough-weather-api
- namespace: apps
-spec:
- apis:
- - name: walkthrough-weather-api
- everyone: true
-```
-
-We'll need to reference this API in the `IngressRoute` with an annotation:
-
-```yaml :src/manifests/walkthrough/api.yaml -s 25 -e 41
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: walkthrough-weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api: walkthrough-weather-api # <=== Link to the API using its name
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.walkthrough.docker.localhost`) && PathPrefix(`/weather`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
-```
-
-:information_source: We've also removed the API Key authentication middleware, as we'll use Traefik Hub's built-in identity provider for user and credential management. The API is still secured, as we'll see it shortly.
-
-Let's apply it:
-
-```shell
-kubectl apply -f src/manifests/walkthrough/api.yaml
-```
-
-It will create `API`, `APIAccess` and link `IngressRoute` to this API.
-
-```shell
-api.hub.traefik.io/walkthrough-weather-api created
-apiaccess.hub.traefik.io/walkthrough-weather-api created
-ingressroute.traefik.io/walkthrough-weather-api created
-```
-
-Now, we can confirm this API is not publicly exposed:
-
-```shell
-curl -i http://api.walkthrough.docker.localhost/weather
-```
-
-It returns the expected 401 Unauthorized HTTP code:
-
-```shell
-HTTP/1.1 401 Unauthorized
-Date: Mon, 06 May 2024 12:09:56 GMT
-Content-Length: 0
-```
-
-## Step 4: Create a user for this API
-
-Users are created in the [Traefik Hub Online Dashboard](https://hub.traefik.io/users):
-
-
-
-## Step 5: Deploy the API Portal
-
-The user created previously will connect to an API Portal to generate an API key, so let's deploy the API Portal!
-
-```yaml :src/manifests/walkthrough/api-portal.yaml
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPortal
-metadata:
- name: walkthrough-apiportal
- namespace: apps
-spec:
- title: API Portal
- description: "Apps Developer Portal"
- trustedUrls:
- - http://api.walkthrough.docker.localhost
-
----
-apiVersion: networking.k8s.io/v1
-kind: Ingress
-metadata:
- name: walkthrough-apiportal
- namespace: traefik
- annotations:
- # This annotation link this Ingress to the API Portal using @ format.
- hub.traefik.io/api-portal: walkthrough-apiportal@apps
-spec:
- rules:
- - host: api.walkthrough.docker.localhost
- http:
- paths:
- - path: /
- pathType: Prefix
- backend:
- service:
- name: apiportal
- port:
- number: 9903
-```
-
-:information_source: This API Portal is routed with the internal _ClusterIP_ `Service` named apiportal.
-
-```shell
-kubectl apply -f src/manifests/walkthrough/api-portal.yaml
-sleep 60
-```
-
-```shell
-apiportal.hub.traefik.io/walkthrough-apiportal created
-ingress.networking.k8s.io/walkthrough-apiportal created
-```
-
-The API Portal should be reachable on http://api.walkthrough.docker.localhost
-
-We log in with the admin user.
-
-
-
-And create a token for this user:
-
-
-
-```shell
-export ADMIN_TOKEN="XXX"
-```
-
-Request the API with this token: :tada:
-
-```shell
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.walkthrough.docker.localhost/weather | jq
-```
-
-```json
-[
- {"city":"GopherTown","id":"0","weather":"Cloudy"},
- {"city":"City of Gophers","id":"1","weather":"Sunny"},
- {"city":"GopherRocks","id":"2","weather":"Cloudy"}
-]
-```
-
-:information_source: If it fails with 401, wait one minute and try again. The token needs to be sync before it can be accepted by Traefik Hub.
-
-We can see the API available in the `apps` namespace in the portal. We advise every API to come with an OpenAPI specification (OAS):
-
-
-
-However, it's still possible not setting an OAS, but it severely hurts getting started with API consumption.
-
-This time, we won't specify any OAS in the API _CRD_:
-
-```yaml :src/manifests/walkthrough/forecast.yaml -s 1 -e 7
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: walkthrough-weather-api-forecast
- namespace: apps
-spec: {}
-```
-
-The other resources are built on the same model, as we can see in [the complete file](https://github.com/traefik/hub/blob/main/api-management/1-getting-started/manifests/forecast.yaml). Let's apply it:
-
-```shell
-kubectl apply -f src/manifests/weather-app-forecast.yaml
-kubectl apply -f src/manifests/walkthrough/forecast.yaml
-```
-
-```shell
-api.hub.traefik.io/walkthrough-weather-api-forecast created
-apiaccess.hub.traefik.io/walkthrough-weather-api-forecast created
-ingressroute.traefik.io/walkthrough-weather-api-forecast created
-```
-
-Request the API with the token:
-
-```shell
-curl -H "Authorization: Bearer $ADMIN_TOKEN" http://api.walkthrough.docker.localhost/forecast/weather
-```
-
-And that's it! This time, we have documentation built from the OpenAPI specification, and we can also interactively try the API with the Try Out functionality.
-
-
diff --git a/api-management/1-getting-started/README.md b/api-management/1-getting-started/README.md
index 05ca0ba..a9bb4c4 100644
--- a/api-management/1-getting-started/README.md
+++ b/api-management/1-getting-started/README.md
@@ -1,397 +1,3 @@
# Getting Started
-For this tutorial, we deploy Traefik Hub API Gateway on a [k3d](https://k3d.io/) cluster. It's possible to use alternatives such as [kind](https://kind.sigs.k8s.io), cloud providers, and others.
-
-First, clone the GitHub repository dedicated to tutorials:
-
-```shell
-git clone https://github.com/traefik/hub.git
-cd hub
-```
-
-## Deploy Kubernetes
-
-### Using k3d
-
-```shell
-k3d cluster create traefik-hub --port 80:80@loadbalancer --port 443:443@loadbalancer --port 8000:8000@loadbalancer --k3s-arg "--disable=traefik@server:0"
-```
-
-### Using Kind
-
-kind requires some configuration to use an IngressController on localhost. See the following example:
-
-
-
-Create the cluster
-
-Ports need to be mapped for HTTP and HTTPS for kind with this config:
-
-```yaml
-kind: Cluster
-apiVersion: kind.x-k8s.io/v1alpha4
-name: traefik-hub
-nodes:
-- role: control-plane
- extraPortMappings:
- - containerPort: 30000
- hostPort: 80
- protocol: TCP
- - containerPort: 30001
- hostPort: 443
- protocol: TCP
-```
-
-```shell
-kind create cluster --config=src/kind/config.yaml
-kubectl cluster-info
-kubectl wait --for=condition=ready nodes traefik-hub-control-plane
-```
-
-Now, add a load balancer (LB) to it:
-
-```shell
-kubectl apply -f src/kind/metallb-native.yaml
-kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=90s
-kubectl apply -f src/kind/metallb-config.yaml
-```
-
-
-
-## Step 1: Install Traefik Hub
-
-First, log in to the [Traefik Hub Online Dashboard](https://hub.traefik.io) and open the page to [create a new gateway](https://hub.traefik.io/gateways/new).
-
-**:warning: Do not install the gateway, but copy the token.**
-
-Then, open a terminal and run these commands to create the required secret:
-
-```shell
-export TRAEFIK_HUB_TOKEN=
-```
-
-```shell
-kubectl create namespace traefik
-kubectl create secret generic traefik-hub-license --namespace traefik --from-literal=token=$TRAEFIK_HUB_TOKEN
-```
-
-Now, install Traefik Hub with Helm:
-
-```shell
-# Add the Helm repository
-helm repo add --force-update traefik https://traefik.github.io/charts
-# Install the Helm chart
-helm install traefik -n traefik --wait \
- --version v34.4.1 \
- --set hub.token=traefik-hub-license \
- --set hub.apimanagement.enabled=true \
- --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.14.1 \
- --set ports.web.nodePort=30000 \
- --set ports.websecure.nodePort=30001 \
- traefik/traefik
-```
-
-**If** Traefik Hub is **already** installed, we can instead upgrade the Traefik Hub instance:
-
-```shell
-# Upgrade CRDs
-kubectl apply --server-side --force-conflicts -k https://github.com/traefik/traefik-helm-chart/traefik/crds/
-# Update the Helm repository
-helm repo add --force-update traefik https://traefik.github.io/charts
-# Upgrade the Helm chart
-helm upgrade traefik -n traefik --wait \
- --version v34.4.1 \
- --set hub.token=traefik-hub-license \
- --set hub.apimanagement.enabled=true \
- --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.14.1 \
- --set ports.web.nodePort=30000 \
- --set ports.websecure.nodePort=30001 \
- traefik/traefik
-```
-
-Now, we can access the local dashboard at http://dashboard.docker.localhost/.
-
-## Step 2: Deploy an API as an Ingress
-
-:information_source: This tutorial implements API using a JSON server in Go; check out the source code [here](https://github.com/traefik/hub/tree/main/src/api-server/).
-
-First, let's deploy a [weather app](https://github.com/traefik/hub/blob/main/src/manifests/weather-app.yaml) exposing an API:
-
-```shell
-kubectl apply -f src/manifests/apps-namespace.yaml
-kubectl apply -f src/manifests/weather-app.yaml
-```
-
-It creates the weather app:
-
-```shell
-namespace/apps unchanged
-configmap/weather-data unchanged
-middleware.traefik.io/stripprefix-weather unchanged
-deployment.apps/weather-app unchanged
-service/weather-app unchanged
-configmap/weather-app-openapispec unchanged
-```
-
-Then, expose the weather app using an `IngressRoute`:
-
-```yaml :manifests/weather-app-ingressroute.yaml
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: getting-started-apimanagement
- namespace: apps
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`getting-started.apimanagement.docker.localhost`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
-```
-
-```shell
-kubectl apply -f api-management/1-getting-started/manifests/weather-app-ingressroute.yaml
-```
-
-```shell
-ingressroute.traefik.io/getting-started-apimanagement created
-```
-
-At this moment, this API is exposed. It's possible to reach it using `curl` command:
-
-```shell
-curl -s http://getting-started.apimanagement.docker.localhost/weather | jq
-```
-
-```json
-[
- {"city":"City of Gophers","id":"1","weather":"Sunny"},
- {"city":"GopherRocks","id":"2","weather":"Cloudy"},
- {"city":"GopherCity","id":"0","weather":"Moderate rain"}
-]
-```
-
-## Step 3: Manage the API using Traefik Hub API Management
-
-Let's manage the weather API with Traefik Hub using `API` and `APIAccess` resources:
-
-```yaml :manifests/api.yaml -s 1 -e 23
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
-spec:
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
- - url: http://api.getting-started.apimanagement.docker.localhost
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
-spec:
- apis:
- - name: getting-started-apimanagement-weather-api
- everyone: true
-```
-
-First, reference the `API` in the `IngressRoute` using the dedicated annotation:
-
-```yaml :manifests/api.yaml -s 25 -e 41
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api: getting-started-apimanagement-weather-api # <=== Link to the API using its name
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.getting-started.apimanagement.docker.localhost`) && PathPrefix(`/weather`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
-```
-
-Now, we can apply the above resources:
-
-```shell
-kubectl apply -f api-management/1-getting-started/manifests/api.yaml
-```
-
-It creates `API`, `APIAccess`, and links `IngressRoute` to the weather API:
-
-```shell
-api.hub.traefik.io/getting-started-apimanagement-weather-api created
-apiaccess.hub.traefik.io/getting-started-apimanagement-weather-api created
-ingressroute.traefik.io/getting-started-apimanagement-weather-api created
-```
-
-Now, the API is secured. When someone tries to access the API, it returns the expected `401 Unauthorized` HTTP code:
-
-```shell
-curl -i http://api.getting-started.apimanagement.docker.localhost/weather
-```
-
-```shell
-HTTP/1.1 401 Unauthorized
-Date: Mon, 06 May 2024 12:09:56 GMT
-Content-Length: 0
-```
-
-## Step 4: Create a user for this API
-
-We can create a user in the [Traefik Hub Online Dashboard](https://hub.traefik.io/users):
-
-
-
-We can provide an API Portal to this user.
-
-## Step 5: Deploy the API Portal
-
-An API Portal use the same logic as an API for the routing, using `Ingress` and dedicated annotation.
-
-:information_source: The portal enforces namespace boundaries and considers only `APIAccess` resources within the same namespace as the `APIPortal`.
-
-```yaml :manifests/api-portal.yaml
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPortal
-metadata:
- name: getting-started-apimanagement-apiportal
- namespace: apps
-spec:
- title: API Portal
- description: "Apps Developer Portal"
- trustedUrls:
- - http://api.getting-started.apimanagement.docker.localhost
-
----
-apiVersion: networking.k8s.io/v1
-kind: Ingress
-metadata:
- name: getting-started-apimanagement-apiportal
- namespace: traefik
- annotations:
- # This annotation link this Ingress to the API Portal using @ format.
- hub.traefik.io/api-portal: getting-started-apimanagement-apiportal@apps
-spec:
- rules:
- - host: api.getting-started.apimanagement.docker.localhost
- http:
- paths:
- - path: /
- pathType: Prefix
- backend:
- service:
- name: apiportal
- port:
- number: 9903
-```
-
-:information_source: This API Portal is routed with the internal _ClusterIP_ `Service` named _apiportal_ provided with the Helm Chart.
-
-```shell
-kubectl apply -f api-management/1-getting-started/manifests/api-portal.yaml
-sleep 30
-```
-
-```shell
-apiportal.hub.traefik.io/getting-started-apimanagement-apiportal created
-ingress.networking.k8s.io/getting-started-apimanagement-apiportal created
-```
-
-The API Portal is reachable on http://api.getting-started.apimanagement.docker.localhost.
-
-Now, we should be able to log in with the admin user and create a token for the user:
-
-
-
-
-
-```shell
-export ADMIN_TOKEN=
-```
-
-The weather API is reachable with this token set as header :tada: :
-
-```shell
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.getting-started.apimanagement.docker.localhost/weather | jq
-```
-
-```json
-[
- {"city":"City of Gophers","id":"1","weather":"Sunny"},
- {"city":"GopherRocks","id":"2","weather":"Cloudy"},
- {"city":"GopherCity","id":"0","weather":"Moderate rain"}
-]
-```
-
-:information_source: If it fails with 401, wait a minute and try again. The token needs to be sync before it can be accepted by Traefik Hub.
-
-We can see the API available in the `apps` namespace in the portal. We advise every API to come with an OpenAPI specification (OAS):
-
-
-
-However, it's still possible not setting an OAS, but it severely hurts getting started with API consumption.
-Let's deploy a [forecast app](https://github.com/traefik/hub/blob/main/src/manifests/weather-app-forecast.yaml) without an OpenAPI specification:
-
-```shell
-kubectl apply -f src/manifests/weather-app-forecast.yaml
-```
-
-This time, we will specify how to get this openapi spec in API _CRD_:
-
-```yaml :manifests/forecast.yaml -s 1 -e 7
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: getting-started-apimanagement-weather-api-forecast
- namespace: apps
-spec: {}
-```
-
-The other resources are built on the same model, as we can see in [the complete file](https://github.com/traefik/hub/blob/main/api-management/1-getting-started/manifests/forecast.yaml). Let's apply it:
-
-```shell
-kubectl apply -f api-management/1-getting-started/manifests/forecast.yaml
-```
-
-```shell
-api.hub.traefik.io/getting-started-apimanagement-weather-api-forecast created
-apiaccess.hub.traefik.io/getting-started-apimanagement-weather-api-forecast created
-ingressroute.traefik.io/getting-started-apimanagement-weather-api-forecast created
-```
-
-And that's it! This time, we have documentation built from the OpenAPI specification, and we can also interactively try the API with the Try Out functionality.
-
-
+Please refer to the [Traefik Hub API Management quick start guide](https://doc.traefik.io/traefik-hub/api-management/quick-start-guide) tutorial.
diff --git a/api-management/1-getting-started/manifests/api.yaml b/api-management/1-getting-started/manifests/api.yaml
deleted file mode 100644
index 6070738..0000000
--- a/api-management/1-getting-started/manifests/api.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
-spec:
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
- - url: http://api.getting-started.apimanagement.docker.localhost
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
-spec:
- apis:
- - name: getting-started-apimanagement-weather-api
- everyone: true
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: getting-started-apimanagement-weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api: getting-started-apimanagement-weather-api # <=== Link to the API using its name
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.getting-started.apimanagement.docker.localhost`) && PathPrefix(`/weather`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
diff --git a/api-management/2-access-control/README.md b/api-management/2-access-control/README.md
deleted file mode 100644
index 2705e21..0000000
--- a/api-management/2-access-control/README.md
+++ /dev/null
@@ -1,364 +0,0 @@
-# Access Control
-
-In this tutorial, we will see how to control access to APIs.
-
-## Simple access control
-
-Let's try a simple example start. Let's say we want to give separate access between an (internal) admin user and an external user with a subscription.
-
-```mermaid
----
-title: Simple access control
----
-graph LR
- admin-user[Admin User] --> admin-app(admin API)
- external-user[External User] --> weather-app(weather API)
-
- %% CSS
- classDef apis fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
- classDef users fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
- class admin-user,external-user users;
- class admin-app,private-app apis;
-```
-
-First, we will deploy the _weather_ app and the _admin_ app:
-
-```shell
-kubectl apply -f src/manifests/apps-namespace.yaml
-kubectl apply -f src/manifests/weather-app.yaml
-kubectl apply -f src/manifests/admin-app.yaml
-```
-
-To ensure isolation between access, there is a versatile `APIAccess` CRD, allowing the linking of user groups and APIs. So, let's declare the _admin_ API with its `APIAccess`:
-
-```yaml :manifests/simple-admin-api.yaml
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
-spec: {}
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
-spec:
- groups: # <=== Allow access only for this group
- - admin
- apis: # <=== Select only this API
- - name: access-control-apimanagement-simple-admin
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
- annotations:
- hub.traefik.io/api: access-control-apimanagement-simple-admin
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathPrefix(`/simple/admin`)
- kind: Rule
- services:
- - name: admin-app
- port: 3000
- middlewares:
- - name: stripprefix-admin
-```
-
-```shell
-kubectl apply -f api-management/2-access-control/manifests/simple-admin-api.yaml
-```
-
-```shell
-api.hub.traefik.io/access-control-apimanagement-simple-admin created
-apiaccess.hub.traefik.io/access-control-apimanagement-simple-admin created
-ingressroute.traefik.io/access-control-apimanagement-simple-admin created
-```
-
-For the _external_ `API` with its `APIAccess`, we'll see how to use a label selector:
-
-```yaml :manifests/simple-weather-api.yaml
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
- labels:
- subscription: standard
-spec:
- openApiSpec:
- path: /openapi.yaml
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
-spec:
- groups:
- - external
- apiSelector: # <======== Select all APIs with label subscription=external
- matchLabels:
- subscription: standard
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
- annotations:
- hub.traefik.io/api: access-control-apimanagement-simple-weather
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathRegexp(`^/simple/weather(/([0-9]+|openapi.yaml))?$`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
-```
-
-```shell
-kubectl apply -f api-management/2-access-control/manifests/simple-weather-api.yaml
-```
-
-```shell
-api.hub.traefik.io/access-control-apimanagement-simple-weather created
-apiaccess.hub.traefik.io/access-control-apimanagement-simple-weather created
-ingressroute.traefik.io/access-control-apimanagement-simple-weather created
-```
-
-### Test it
-
-First, we'll need to create the _admin_ user in the _admin_ group and the _external_ user in the _external_ group, following instructions in [getting started](../1-getting-started/README.md)
-
-Now, we can test it with the users' API tokens.
-
-```shell
-export ADMIN_TOKEN=
-export EXTERNAL_TOKEN=
-```
-
-```shell
-# This call is allowed => 200
-curl -i -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.access-control.apimanagement.docker.localhost/simple/admin"
-# This call is forbidden => 403
-curl -i -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.access-control.apimanagement.docker.localhost/simple/weather"
-```
-
-```shell
-# This call is allowed => 200
-curl -i -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.access-control.apimanagement.docker.localhost/simple/weather"
-# This call is forbidden => 403
-curl -i -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.access-control.apimanagement.docker.localhost/simple/admin"
-```
-
-:information_source: If it fails, just wait one minute and try again. The token needs to be sync before it can be accepted by Traefik Hub.
-
-## Advanced access control
-
-This second example is more complex, but it's also more secure, using Operation Filters.
-
-* _admin_ can get and update weather data on **private-app** and access without restriction on **admin-app**
-* _external_ user can only get data on **weather-app**
-
-```mermaid
----
-title: Advanced access control
----
-graph LR
- admin-user[Admin User] -->|ALL| admin-app(admin API)
- admin-user -->|GET,PUT| weather-app
- external-user[External User] --> |GET| weather-app(weather API)
-
- %% CSS
- classDef apis fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff;
- classDef users fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5;
- class admin-user,external-user users;
- class admin-app,weather-app apis;
-```
-
-One needs to define operationSets to configure operationFilters. Here, we'll differentiate **GET** and **PATCH** HTTP methods.
-
-```diff :../../hack/diff.sh -r -a "manifests/simple-weather-api.yaml manifests/complex-weather-api.yaml"
---- manifests/simple-weather-api.yaml
-+++ manifests/complex-weather-api.yaml
-@@ -2,40 +2,69 @@
- apiVersion: hub.traefik.io/v1alpha1
- kind: API
- metadata:
-- name: access-control-apimanagement-simple-weather
-+ name: access-control-apimanagement-complex-weather
- namespace: apps
- labels:
- subscription: standard
- spec:
- openApiSpec:
- path: /openapi.yaml
-+ operationSets:
-+ - name: get-forecast
-+ matchers:
-+ - pathPrefix: "/weather"
-+ methods: [ "GET" ]
-+ - name: patch-forecast
-+ matchers:
-+ - pathPrefix: "/weather/0"
-+ methods: [ "PATCH" ]
-
- ---
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-- name: access-control-apimanagement-simple-weather
-+ name: access-control-apimanagement-complex-weather-external
- namespace: apps
- spec:
- groups:
- - external
-- apiSelector: # <======== Select all APIs with label subscription=external
-+ apiSelector:
- matchLabels:
- subscription: standard
-+ operationFilter:
-+ include:
-+ - get-forecast
-+
-+---
-+apiVersion: hub.traefik.io/v1alpha1
-+kind: APIAccess
-+metadata:
-+ name: access-control-apimanagement-complex-weather-admin
-+ namespace: apps
-+spec:
-+ groups:
-+ - admin
-+ apiSelector:
-+ matchLabels:
-+ subscription: standard
-+ operationFilter:
-+ include:
-+ - get-forecast
-+ - patch-forecast
-
- ---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: access-control-apimanagement-simple-weather
-+ name: access-control-apimanagement-complex-weather
- namespace: apps
- annotations:
-- hub.traefik.io/api: access-control-apimanagement-simple-weather
-+ hub.traefik.io/api: access-control-apimanagement-complex-weather
- spec:
- entryPoints:
- - web
- routes:
-- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathRegexp(`^/simple/weather(/([0-9]+|openapi.yaml))?$`)
-+ - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathRegexp(`^/complex/weather(/([0-9]+|openapi.yaml))?$`)
- kind: Rule
- services:
- - name: weather-app
-```
-
-### Deploy and test it
-
-After deploying it:
-
-```shell
-kubectl apply -f api-management/2-access-control/manifests/complex-weather-api.yaml
-kubectl apply -f api-management/2-access-control/manifests/complex-admin-api.yaml
-```
-
-It can be tested with the API token of the admin:
-
-```shell
-# This call is allowed.
-curl -i -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/admin"
-# This call is now allowed
-curl -i -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/weather"
-# And even PATCH is allowed
-curl -i -XPATCH -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/weather/0" -d '[{"op": "replace", "path": "/city", "value": "GopherTown"}]'
-```
-
-And test it with the external user's token:
-
-```shell
-# This one is allowed
-curl -i -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/weather"
-# And PATCH should be not allowed
-curl -i -XPATCH -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/weather/0" -d '[{"op": "replace", "path": "/weather", "value": "Cloudy"}]'
-```
-
-It can be explained quite easily if **PATCH** is still allowed. There is still an `APIAccess` created with the simple tutorial:
-
-```yaml
-kubectl get apiaccess -n apps
-NAME AGE
-getting-started-apimanagement-weather-api 86m
-getting-started-apimanagement-weather-api-forecast 9m1s
-access-control-apimanagement-simple-weather 6m15s
-access-control-apimanagement-complex-weather-external 54s
-access-control-apimanagement-complex-weather-admin 54s
-```
-
-It means that for the `external` user group, there are two `APIAccess` applying:
-
-This is the first one:
-
-```yaml :manifests/simple-weather-api.yaml -s 13 -e 24
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
-spec:
- groups:
- - external
- apiSelector: # <======== Select all APIs with label subscription=external
- matchLabels:
- subscription: standard
-```
-
-And this is the second one:
-
-```yaml :manifests/complex-weather-api.yaml -s 22 -e 36
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-complex-weather-external
- namespace: apps
-spec:
- groups:
- - external
- apiSelector:
- matchLabels:
- subscription: standard
- operationFilter:
- include:
- - get-forecast
-```
-
-The first one allows all kinds of HTTP requests. If we delete it, the _external_ user can no longer call the API with the **PATCH** HTTP verb.
-
-```shell
-kubectl delete apiaccess -n apps access-control-apimanagement-simple-weather
-# This time, PATCH is not allowed
-curl -i -XPATCH -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.access-control.apimanagement.docker.localhost/complex/weather/0" -d '[{"op": "replace", "path": "/weather", "value": "Cloudy"}]'
-```
diff --git a/api-management/2-access-control/manifests/complex-admin-api.yaml b/api-management/2-access-control/manifests/complex-admin-api.yaml
deleted file mode 100644
index 53c77a8..0000000
--- a/api-management/2-access-control/manifests/complex-admin-api.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-complex-admin
- namespace: admin
-spec: {}
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-complex-admin
- namespace: admin
-spec:
- groups: # <=== Allow access only for this group
- - admin
- apis: # <=== Select only this API
- - name: access-control-apimanagement-complex-admin
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-complex-admin
- namespace: admin
- annotations:
- hub.traefik.io/api: access-control-apimanagement-complex-admin
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathPrefix(`/complex/admin`)
- kind: Rule
- services:
- - name: admin-app
- port: 3000
- middlewares:
- - name: stripprefix-admin
diff --git a/api-management/2-access-control/manifests/complex-weather-api.yaml b/api-management/2-access-control/manifests/complex-weather-api.yaml
deleted file mode 100644
index cb2e77b..0000000
--- a/api-management/2-access-control/manifests/complex-weather-api.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-complex-weather
- namespace: apps
- labels:
- subscription: standard
-spec:
- openApiSpec:
- path: /openapi.yaml
- operationSets:
- - name: get-forecast
- matchers:
- - pathPrefix: "/weather"
- methods: [ "GET" ]
- - name: patch-forecast
- matchers:
- - pathPrefix: "/weather/0"
- methods: [ "PATCH" ]
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-complex-weather-external
- namespace: apps
-spec:
- groups:
- - external
- apiSelector:
- matchLabels:
- subscription: standard
- operationFilter:
- include:
- - get-forecast
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-complex-weather-admin
- namespace: apps
-spec:
- groups:
- - admin
- apiSelector:
- matchLabels:
- subscription: standard
- operationFilter:
- include:
- - get-forecast
- - patch-forecast
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-complex-weather
- namespace: apps
- annotations:
- hub.traefik.io/api: access-control-apimanagement-complex-weather
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathRegexp(`^/complex/weather(/([0-9]+|openapi.yaml))?$`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/2-access-control/manifests/simple-admin-api.yaml b/api-management/2-access-control/manifests/simple-admin-api.yaml
deleted file mode 100644
index 1d64615..0000000
--- a/api-management/2-access-control/manifests/simple-admin-api.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
-spec: {}
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
-spec:
- groups: # <=== Allow access only for this group
- - admin
- apis: # <=== Select only this API
- - name: access-control-apimanagement-simple-admin
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-simple-admin
- namespace: admin
- annotations:
- hub.traefik.io/api: access-control-apimanagement-simple-admin
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathPrefix(`/simple/admin`)
- kind: Rule
- services:
- - name: admin-app
- port: 3000
- middlewares:
- - name: stripprefix-admin
diff --git a/api-management/2-access-control/manifests/simple-weather-api.yaml b/api-management/2-access-control/manifests/simple-weather-api.yaml
deleted file mode 100644
index 0f3103a..0000000
--- a/api-management/2-access-control/manifests/simple-weather-api.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
- labels:
- subscription: standard
-spec:
- openApiSpec:
- path: /openapi.yaml
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
-spec:
- groups:
- - external
- apiSelector: # <======== Select all APIs with label subscription=external
- matchLabels:
- subscription: standard
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: access-control-apimanagement-simple-weather
- namespace: apps
- annotations:
- hub.traefik.io/api: access-control-apimanagement-simple-weather
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.access-control.apimanagement.docker.localhost`) && PathRegexp(`^/simple/weather(/([0-9]+|openapi.yaml))?$`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/3-api-lifecycle-management/README.md b/api-management/3-api-lifecycle-management/README.md
deleted file mode 100644
index 2e6e9eb..0000000
--- a/api-management/3-api-lifecycle-management/README.md
+++ /dev/null
@@ -1,388 +0,0 @@
-# API LifeCycle Management
-
-In this tutorial, we will see how to publish a new version of an API.
-
-## Deploy an API
-
-First, we'll deploy the API in _getting started_:
-
-```shell
-kubectl apply -f src/manifests/apps-namespace.yaml
-kubectl apply -f src/manifests/weather-app.yaml
-kubectl apply -f api-management/3-api-lifecycle-management/manifests/api.yaml
-```
-
-```shell
-namespace/apps unchanged
-configmap/weather-data unchanged
-middleware.traefik.io/stripprefix-weather unchanged
-deployment.apps/weather-app unchanged
-service/weather-app unchanged
-configmap/weather-app-openapispec unchanged
-api.hub.traefik.io/api-lifecycle-apimanagement-weather-api created
-apiaccess.hub.traefik.io/api-lifecycle-apimanagement-weather-api created
-ingressroute.traefik.io/api-lifecycle-apimanagement-weather-api created
-```
-
-And confirms it works as expected:
-
-```shell
-export ADMIN_TOKEN=
-```
-
-```shell
-# This call is not allowed
-curl -i http://api.lifecycle.apimanagement.docker.localhost/weather
-# This call is allowed
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather | jq
-```
-
-## Publish the first API Version
-
-To use API Version features, we'll need to:
-
-1. Declare an `APIVersion`
-2. Reference it into the `API`
-3. Use it in the routing
-
-```diff :../../hack/diff.sh -r -a "manifests/api.yaml manifests/api-v1.yaml"
---- manifests/api.yaml
-+++ manifests/api-v1.yaml
-@@ -1,41 +1,54 @@
- ---
- apiVersion: hub.traefik.io/v1alpha1
--kind: API
-+kind: APIVersion
- metadata:
-- name: api-lifecycle-apimanagement-weather-api
-+ name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
- spec:
-+ release: v1.0.0
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
-- - url: http://api.lifecycle.apimanagement.docker.localhost
-+ - url: http://api.lifecycle.apimanagement.docker.localhost/weather-v1
-+
-+---
-+apiVersion: hub.traefik.io/v1alpha1
-+kind: API
-+metadata:
-+ name: api-lifecycle-apimanagement-weather-api-v1
-+ namespace: apps
-+spec:
-+ versions:
-+ - name: api-lifecycle-apimanagement-weather-api-v1
-
- ---
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-- name: api-lifecycle-apimanagement-weather-api
-+ name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
- spec:
- apis:
-- - name: api-lifecycle-apimanagement-weather-api
-+ - name: api-lifecycle-apimanagement-weather-api-v1
- everyone: true
-
- ---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: api-lifecycle-apimanagement-weather-api
-+ name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
- annotations:
-- hub.traefik.io/api: api-lifecycle-apimanagement-weather-api # <=== Link to the API using its name
-+ hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1
- spec:
- entryPoints:
- - web
- routes:
-- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather`)
-+ - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-v1`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
-+ middlewares:
-+ - name: stripprefix-weather
-```
-
-We can apply it:
-
-```shell
-kubectl apply -f api-management/3-api-lifecycle-management/manifests/api-v1.yaml
-```
-
-```shell
-apiversion.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1 created
-api.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1 created
-apiaccess.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1 created
-ingressroute.traefik.io/api-lifecycle-apimanagement-weather-api-v1 created
-```
-
-And confirm it's still working:
-
-```shell
-# This call is not allowed
-curl -i http://api.lifecycle.apimanagement.docker.localhost/weather-v1/weather
-# This call is allowed
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-v1/weather | jq
-```
-
-## Publish a second API Version
-
-Now, let's say a new version is available. We'll need to test whether everything is OK before making it go to production.
-
-So, for this second API Version, we'll need to:
-
-1. Deploy this new version
-2. Declare an `APIVersion`
-3. Reference it into the `API`
-4. Create a new `IngressRoute` requiring a special header
-
-```diff :../../hack/diff.sh -r -a "manifests/api-v1.yaml manifests/api-v1.1.yaml"
---- manifests/api-v1.yaml
-+++ manifests/api-v1.1.yaml
-@@ -2,42 +2,38 @@
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIVersion
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1
-+ name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
- spec:
-- release: v1.0.0
-- openApiSpec:
-- path: /openapi.yaml
-- override:
-- servers:
-- - url: http://api.lifecycle.apimanagement.docker.localhost/weather-v1
-+ release: v1.1.0
-
- ---
- apiVersion: hub.traefik.io/v1alpha1
- kind: API
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1
-+ name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
- spec:
- versions:
- - name: api-lifecycle-apimanagement-weather-api-v1
-+ - name: api-lifecycle-apimanagement-weather-api-v1-1
-
- ---
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1
-+ name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
- spec:
- apis:
-- - name: api-lifecycle-apimanagement-weather-api-v1
-+ - name: api-lifecycle-apimanagement-weather-api-v1-1
- everyone: true
-
- ---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1
-+ name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1
-@@ -45,10 +41,30 @@
- entryPoints:
- - web
- routes:
-- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-v1`)
-+ - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
-+
-+---
-+apiVersion: traefik.io/v1alpha1
-+kind: IngressRoute
-+metadata:
-+ name: api-lifecycle-apimanagement-weather-api-v1-1-preview
-+ namespace: apps
-+ annotations:
-+ hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1-1
-+spec:
-+ entryPoints:
-+ - web
-+ routes:
-+ - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`) && Header(`X-Version`, `preview`)
-+ kind: Rule
-+ services:
-+ - name: weather-app-forecast
-+ port: 3000
-+ middlewares:
-+ - name: stripprefix-weather
-```
-
-So let's do it:
-
-```shell
-kubectl apply -f src/manifests/weather-app-forecast.yaml
-kubectl apply -f api-management/3-api-lifecycle-management/manifests/api-v1.1.yaml
-```
-
-```shell
-configmap/weather-app-forecast-data unchanged
-deployment.apps/weather-app-forecast unchanged
-service/weather-app-forecast unchanged
-apiversion.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1-1 created
-api.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1-1 created
-apiaccess.hub.traefik.io/api-lifecycle-apimanagement-weather-api-v1-1 created
-ingressroute.traefik.io/api-lifecycle-apimanagement-weather-api-v1-1 created
-ingressroute.traefik.io/api-lifecycle-apimanagement-weather-api-v1-1-preview created
-```
-
-Now, we can test if it works:
-
-```shell
-# Even with preview X-Version header, it should return 401 without token
-curl -i -H "X-Version: preview" http://api.lifecycle.apimanagement.docker.localhost/weather-multi-versions/weather
-# Regular access => returns weather data
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-multi-versions/weather | jq
-# Preview access, with special header => returns forecast data
-curl -s -H "X-Version: preview" -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-multi-versions/weather | jq
-```
-
-To go further, one can use this pattern with other Traefik Middlewares to route versions based on many parameters: path, query, content type, clientIP, basicAuth, forwardAuth, and many others!
-
-## Try the new version with a part of the traffic
-
-Once this new version is adequately tested, we'll want to put it in production. We'll distribute the traffic among the two versions to see if it can handle the load.
-
-To achieve this goal, we'll need to:
-
-1. Remove test `IngressRoute` weather-api-v1-1
-2. Declare a Weighted Round Robin TraefikService for load balancing
-3. Use it in the `IngressRoute`
-
-Since the last step, the diff is looking like this:
-
-```diff :../../hack/diff.sh -r -a "manifests/api-v1.1.yaml manifests/api-v1.1-weighted.yaml"
---- manifests/api-v1.1.yaml
-+++ manifests/api-v1.1-weighted.yaml
-@@ -1,59 +1,24 @@
- ---
--apiVersion: hub.traefik.io/v1alpha1
--kind: APIVersion
--metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1-1
-- namespace: apps
--spec:
-- release: v1.1.0
--
-----
--apiVersion: hub.traefik.io/v1alpha1
--kind: API
--metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1-1
-- namespace: apps
--spec:
-- versions:
-- - name: api-lifecycle-apimanagement-weather-api-v1
-- - name: api-lifecycle-apimanagement-weather-api-v1-1
--
-----
--apiVersion: hub.traefik.io/v1alpha1
--kind: APIAccess
--metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1-1
-- namespace: apps
--spec:
-- apis:
-- - name: api-lifecycle-apimanagement-weather-api-v1-1
-- everyone: true
--
-----
- apiVersion: traefik.io/v1alpha1
--kind: IngressRoute
-+kind: TraefikService
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1-1
-+ name: api-lifecycle-apimanagement-weather-api-wrr
- namespace: apps
-- annotations:
-- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1
- spec:
-- entryPoints:
-- - web
-- routes:
-- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`)
-- kind: Rule
-+ weighted:
- services:
-- - name: weather-app
-- port: 3000
-- middlewares:
-- - name: stripprefix-weather
-+ - name: weather-app
-+ port: 3000
-+ weight: 1
-+ - name: weather-app-forecast
-+ port: 3000
-+ weight: 1
-
- ---
- apiVersion: traefik.io/v1alpha1
- kind: IngressRoute
- metadata:
-- name: api-lifecycle-apimanagement-weather-api-v1-1-preview
-+ name: weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1-1
-@@ -61,10 +26,11 @@
- entryPoints:
- - web
- routes:
-- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`) && Header(`X-Version`, `preview`)
-+ - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-v1-wrr`)
- kind: Rule
- services:
-- - name: weather-app-forecast
-+ - name: api-lifecycle-apimanagement-weather-api-wrr
- port: 3000
-+ kind: TraefikService
- middlewares:
- - name: stripprefix-weather
-```
-
-Let's apply it:
-
-```shell
-kubectl apply -f api-management/3-api-lifecycle-management/manifests/api-v1.1-weighted.yaml
-```
-
-```shell
-traefikservice.traefik.io/api-lifecycle-apimanagement-weather-api-wrr created
-ingressroute.traefik.io/weather-api created
-```
-
-A simple test should confirm that it works:
-
-```shell
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-v1-wrr/weather | jq
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-v1-wrr/weather | jq
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-v1-wrr/weather | jq
-curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://api.lifecycle.apimanagement.docker.localhost/weather-v1-wrr/weather | jq
-```
-
-To go further, it's also possible to mirror production traffic to a new version and/or to use a sticky session.
diff --git a/api-management/3-api-lifecycle-management/manifests/api-portal.yaml b/api-management/3-api-lifecycle-management/manifests/api-portal.yaml
deleted file mode 100644
index 433b252..0000000
--- a/api-management/3-api-lifecycle-management/manifests/api-portal.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPortal
-metadata:
- name: api-lifecycle-apimanagement-apiportal
- namespace: apps
-spec:
- title: API Portal
- description: "Apps Developer Portal"
- trustedUrls:
- - http://api.lifecycle.apimanagement.docker.localhost
-
----
-apiVersion: networking.k8s.io/v1
-kind: Ingress
-metadata:
- name: api-lifecycle-apimanagement-apiportal
- namespace: traefik
- annotations:
- # This annotation link this Ingress to the API Portal using @ format.
- hub.traefik.io/api-portal: api-lifecycle-apimanagement-apiportal@apps
-spec:
- rules:
- - host: api.lifecycle.apimanagement.docker.localhost
- http:
- paths:
- - path: /
- pathType: Prefix
- backend:
- service:
- name: apiportal
- port:
- number: 9903
diff --git a/api-management/3-api-lifecycle-management/manifests/api-v1.1-weighted.yaml b/api-management/3-api-lifecycle-management/manifests/api-v1.1-weighted.yaml
deleted file mode 100644
index 5744dfe..0000000
--- a/api-management/3-api-lifecycle-management/manifests/api-v1.1-weighted.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
----
-apiVersion: traefik.io/v1alpha1
-kind: TraefikService
-metadata:
- name: api-lifecycle-apimanagement-weather-api-wrr
- namespace: apps
-spec:
- weighted:
- services:
- - name: weather-app
- port: 3000
- weight: 1
- - name: weather-app-forecast
- port: 3000
- weight: 1
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1-1
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-v1-wrr`)
- kind: Rule
- services:
- - name: api-lifecycle-apimanagement-weather-api-wrr
- port: 3000
- kind: TraefikService
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/3-api-lifecycle-management/manifests/api-v1.1.yaml b/api-management/3-api-lifecycle-management/manifests/api-v1.1.yaml
deleted file mode 100644
index db0fbf6..0000000
--- a/api-management/3-api-lifecycle-management/manifests/api-v1.1.yaml
+++ /dev/null
@@ -1,70 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIVersion
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
-spec:
- release: v1.1.0
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
-spec:
- versions:
- - name: api-lifecycle-apimanagement-weather-api-v1
- - name: api-lifecycle-apimanagement-weather-api-v1-1
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
-spec:
- apis:
- - name: api-lifecycle-apimanagement-weather-api-v1-1
- everyone: true
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1-1
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1-1-preview
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1-1
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-multi-versions`) && Header(`X-Version`, `preview`)
- kind: Rule
- services:
- - name: weather-app-forecast
- port: 3000
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/3-api-lifecycle-management/manifests/api-v1.yaml b/api-management/3-api-lifecycle-management/manifests/api-v1.yaml
deleted file mode 100644
index e64e732..0000000
--- a/api-management/3-api-lifecycle-management/manifests/api-v1.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIVersion
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
-spec:
- release: v1.0.0
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
- - url: http://api.lifecycle.apimanagement.docker.localhost/weather-v1
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
-spec:
- versions:
- - name: api-lifecycle-apimanagement-weather-api-v1
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
-spec:
- apis:
- - name: api-lifecycle-apimanagement-weather-api-v1
- everyone: true
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: api-lifecycle-apimanagement-weather-api-v1
- namespace: apps
- annotations:
- hub.traefik.io/api-version: api-lifecycle-apimanagement-weather-api-v1
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather-v1`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/3-api-lifecycle-management/manifests/api.yaml b/api-management/3-api-lifecycle-management/manifests/api.yaml
deleted file mode 100644
index 656818e..0000000
--- a/api-management/3-api-lifecycle-management/manifests/api.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: api-lifecycle-apimanagement-weather-api
- namespace: apps
-spec:
- openApiSpec:
- path: /openapi.yaml
- override:
- servers:
- - url: http://api.lifecycle.apimanagement.docker.localhost
-
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: api-lifecycle-apimanagement-weather-api
- namespace: apps
-spec:
- apis:
- - name: api-lifecycle-apimanagement-weather-api
- everyone: true
-
----
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: api-lifecycle-apimanagement-weather-api
- namespace: apps
- annotations:
- hub.traefik.io/api: api-lifecycle-apimanagement-weather-api # <=== Link to the API using its name
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.lifecycle.apimanagement.docker.localhost`) && PathPrefix(`/weather`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
diff --git a/api-management/4-protect-api-infrastructure/README.md b/api-management/4-protect-api-infrastructure/README.md
deleted file mode 100644
index 0e82f6c..0000000
--- a/api-management/4-protect-api-infrastructure/README.md
+++ /dev/null
@@ -1,560 +0,0 @@
-# Protect API infrastructure
-
-In this tutorial, we will learn how to protect our APIs from excessive usage using API Plans in Traefik Hub’s API Management.
-By following these steps, we’ll ensure that our APIs remain performant and are not overwhelmed by excessive requests.
-
-By the end of this tutorial, we’ll be able to:
-
-- Protect our APIs from excessive usage by implementing rate limits and quotas using API Plans.
-- Manage API Plans to provide different levels of service to various consumer groups.
-
-## What are our APIs ?
-
-In this tutorial, we will use two APIs:
-
-1. `admin` API: It's internal and not really reliable. It should not take more than one request per second
-2. `weather` API: It's exposed externally. Users can be billed for this one, up to 500 requests each day.
-
-## Pre-requisites
-
-- Traefik Hub should be installed with API Management following [getting started](../1-getting-started/README.md) instructions
-- Follow the [Access Control](../2-access-control/README.md) tutorial to set up the users and API portal we will need in this tutorial
-
-### Step 1: Deploy `weather` and `admin` apps and APIs
-
-First, deploy the weather app and the admin app, with an API Access. It follows the simple access control that is detailed in the [Access Control Tutorial](../2-access-control/README.md).
-
-```sh
-kubectl apply -f src/manifests/apps-namespace.yaml
-kubectl apply -f src/manifests/weather-app.yaml
-kubectl apply -f src/manifests/admin-app.yaml
-kubectl wait -n apps --for=condition=ready pod --selector=app=weather-app --timeout=90s
-kubectl wait -n admin --for=condition=ready pod --selector=app=admin-app --timeout=90s
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/admin-api.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/admin-apiaccess.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/admin-ingressroute.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-api.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-apiaccess.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-ingressroute.yaml
-```
-
-### Step 2: Check Access Control
-
-Those two APIs should be deployed with an access control. Let's check that!
-
-You'll need to get the token for the admin user in the admin group and the external user in the external group, following instructions in the [access control](../2-access-control/README.md) tutorial.
-
-```sh
-# Set here after "=" the token of admin user
-export ADMIN_TOKEN=
-# Set here after "=" the token of external user
-export EXTERNAL_TOKEN=
-```
-
-Admin user is only allowed to access admin API:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-# This call is forbidden => 403
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-```
-
-External user is only allowed to access external API:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-# This call is forbidden => 403
-curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-```
-
-### Step 3: Set up Redis
-
-To use the API plan feature, we need to deploy and configure Redis in your cluster and the Traefik deployment.
-
-We can do that by following the instructions in the [official documentation.](https://doc.traefik.io/traefik-hub/api-management/api-plans#prerequisites)
-
-## Protect from excessive usage
-
-### RateLimit on Admin
-
-In order to set rate limit on an API, we'll need to create an API Plan. This API Plan should be associated with an `APIAccess` resource.
-
-```yaml :manifests/admin-apiplan.yaml
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: admin
- namespace: admin
-spec:
- title: "Admin Protection"
- description: "Admin API should not take more than one request per second."
- rateLimit:
- limit: 1
- period: 1s
-```
-
-And link it in the API Access
-
-```diff :../../hack/diff.sh -r -a "manifests/admin-apiaccess.yaml manifests/admin-apiaccess-ratelimit.yaml"
---- manifests/admin-apiaccess.yaml
-+++ manifests/admin-apiaccess-ratelimit.yaml
-@@ -1,10 +1,12 @@
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-- name: protect-api-infrastructure-apimanagement-admin
-+ name: protect-api-infrastructure-apimanagement-admin-ratelimit
- namespace: admin
- spec:
- groups:
- - admin
- apis:
- - name: protect-api-infrastructure-apimanagement-admin
-+ apiPlan:
-+ name: admin
-```
-
-Let's apply it:
-
-```shell
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/admin-apiplan.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/admin-apiaccess-ratelimit.yaml
-```
-
-And test it:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 55
-Content-Type: text/plain; charset=utf-8
-```
-
-:warning: We can see here that the API plan is not working yet because we do not get any HTTP header showing us our Rate Limit remaining as mentioned in the [documentation](https://doc.traefik.io/traefik-hub/api-management/api-plans#response-headers).
-
-Let's try to understand why.
-
-We can check the API Access:
-
-```sh
-kubectl get apiaccess -n admin
-```
-
-```sh
-protect-api-infrastructure-apimanagement-admin 23m
-protect-api-infrastructure-apimanagement-admin-ratelimit 98s
-```
-
-It seems we have two API Access. When multiple `APIAccess` overlap, the [documentation](https://doc.traefik.io/traefik-hub/api-management/api-plans#managing-overlapping-plans) says:
-
-> If the weights were equal or not set for both APIAccess resources, the system would select the one whose name comes first alphabetically.
-
-So Traefik Hub is using the first one in alphabetical order (`protect-api-infrastructure-apimanagement-admin`), without the `APIPlan`.
-
-Let's see what happens when we delete the first one:
-
-```sh
-kubectl delete apiaccess -n admin protect-api-infrastructure-apimanagement-admin
-```
-
-Let's test it again:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 55
-Content-Type: text/plain; charset=utf-8
-X-Ratelimit-Remaining: 0
-```
-
-Yeah, it works :tada: ! We can see the HTTP header `X-Ratelimit-Remaining`. Since we have enforced one request per second, there is 0 left. If we do it twice in a row, the second one will be rejected:
-
-```sh
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-curl -sIXGET -H "Authorization: Bearer $ADMIN_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/admin"
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 55
-Content-Type: text/plain; charset=utf-8
-X-Ratelimit-Remaining: 0
-
-HTTP/1.1 429 Too Many Requests
-X-Ratelimit-Remaining: 0
-Content-Length: 0
-```
-
-We can see the second one was rejected. Within an application, it can wait for a bit of time before re-trying the request.
-
-Now, let's see how to use quota.
-
-### Quota on external API
-
-In order to set a quota on the weather API that is exposed externally, we'll need to create another API Plan. This API Plan should be associated with an `APIAccess` resource.
-
-> [!NOTE]
-> Ratelimit and Quota can also be configured in the same API Plan depending on your use case.
-
-```yaml :manifests/weather-apiplan.yaml
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: external
- namespace: apps
-spec:
- title: "Weather Protection for external users"
- description: "Weather API should not take more than 5 requests in 24 hours"
- quota:
- limit: 5
- period: 24h
-```
-
-And link it in the API Access:
-
-```diff :../../hack/diff.sh -r -a "manifests/weather-apiaccess.yaml manifests/weather-apiaccess-quota.yaml"
---- manifests/weather-apiaccess.yaml
-+++ manifests/weather-apiaccess-quota.yaml
-@@ -1,11 +1,12 @@
-----
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-- name: protect-api-infrastructure-apimanagement-weather
-+ name: protect-api-infrastructure-apimanagement-weather-quota
- namespace: apps
- spec:
- groups:
- - external
- apis:
- - name: protect-api-infrastructure-apimanagement-weather
-+ apiPlan:
-+ name: external
-```
-
-Let's apply it:
-
-```yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-apiplan.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota.yaml
-```
-
-And test it:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-```
-
-:warning: We can see here that the API plan is not working yet!
-
-Just like we faced when we were applying [rate limiting](#ratelimit-on-admin) on the admin API, we have to delete the first API Access we applied for weather.
-
-```sh
-kubectl delete apiaccess -n apps protect-api-infrastructure-apimanagement-weather
-```
-
-Let's test it again:
-
-```sh
-# This call is allowed => 200
-curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-X-Quota-Remaining: 3
-```
-
-This time it works and now we can see that there's a new header `X-Quota-Remaining: 3` that specifies our quota.
-
-Now, what happens when we exhaust our quota? Can we still make API requests?
-
-Let's try to exhaust our quota like this:
-
-```sh
-for i in {1..6}; do
- curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-done
-```
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-X-Quota-Remaining: 2
-
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-X-Quota-Remaining: 1
-
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-X-Quota-Remaining: 0
-
-HTTP/1.1 429 Too Many Requests
-X-Quota-Remaining: 0
-Content-Length: 0
-
-HTTP/1.1 429 Too Many Requests
-X-Quota-Remaining: 0
-Content-Length: 0
-
-HTTP/1.1 429 Too Many Requests
-X-Quota-Remaining: 0
-Content-Length: 0
-```
-
-Well, we can see that after we exhaust our quota, we cannot make any more requests to the API, we get a HTTP status code of `429 too many requests`.
-
-We will only be able to make requests again in 24 hours like our API plan specifies or if we subscribe to a new plan.
-
-Why don't we subscribe to a new plan?
-
-Let's create a new API plan called `premium-plan` with a higher quota:
-
-```yaml :manifests/weather-apiplan-premium.yaml
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: external-premium
- namespace: apps
-spec:
- title: "Premium Weather API Plan for external users"
- description: "Weather API should not take more than 500 requests in 24 hours"
- quota:
- limit: 500
- period: 24h
-```
-
-And we need to associate this new `APIPlan` with with the same `APIAccess`:
-
-```diff :../../hack/diff.sh -r -a "manifests/weather-apiaccess-quota.yaml manifests/weather-apiaccess-quota-premium.yaml"
---- manifests/weather-apiaccess-quota.yaml
-+++ manifests/weather-apiaccess-quota-premium.yaml
-@@ -1,3 +1,4 @@
-+---
- apiVersion: hub.traefik.io/v1alpha1
- kind: APIAccess
- metadata:
-@@ -9,4 +10,4 @@
- apis:
- - name: protect-api-infrastructure-apimanagement-weather
- apiPlan:
-- name: external
-+ name: external-premium
-```
-
-Let's apply the new `APIPlan` and the updated `APIAccess`:
-
-```sh
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-apiplan-premium.yaml
-kubectl apply -f api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota-premium.yaml
-```
-
-If we make a request again:
-
-```sh
-curl -sIXGET -H "Authorization: Bearer $EXTERNAL_TOKEN" "http://api.protect-infrastructure.apimanagement.docker.localhost/weather"
-```
-
-We get this output now:
-
-```sh
-HTTP/1.1 200 OK
-Content-Length: 163
-Content-Type: text/plain; charset=utf-8
-X-Quota-Remaining: 494
-```
-
-Yeah, it works now! :tada:
-
-We can see the HTTP header `X-Quota-Remaining: 494` is present, so our new API Plan is in effect.
-
-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 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.
-
-
-
-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 API listed and the API plans available to it.
-
-
-
-If you click on **Multiple plans applied**, you should see all the plans we have applied to the `weather` API.
-
-
-
-## 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.
-
-
-
-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.
-
-
-
-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.
diff --git a/api-management/4-protect-api-infrastructure/images/api-bundle.png b/api-management/4-protect-api-infrastructure/images/api-bundle.png
deleted file mode 100644
index 569b193..0000000
Binary files a/api-management/4-protect-api-infrastructure/images/api-bundle.png and /dev/null differ
diff --git a/api-management/4-protect-api-infrastructure/images/api-plans.png b/api-management/4-protect-api-infrastructure/images/api-plans.png
deleted file mode 100644
index f3a6bbf..0000000
Binary files a/api-management/4-protect-api-infrastructure/images/api-plans.png and /dev/null differ
diff --git a/api-management/4-protect-api-infrastructure/images/api-portal-bundle.png b/api-management/4-protect-api-infrastructure/images/api-portal-bundle.png
deleted file mode 100644
index 753e9d8..0000000
Binary files a/api-management/4-protect-api-infrastructure/images/api-portal-bundle.png and /dev/null differ
diff --git a/api-management/4-protect-api-infrastructure/images/api-portal.png b/api-management/4-protect-api-infrastructure/images/api-portal.png
deleted file mode 100644
index d74097f..0000000
Binary files a/api-management/4-protect-api-infrastructure/images/api-portal.png and /dev/null differ
diff --git a/api-management/4-protect-api-infrastructure/images/multiple-plans-applied.png b/api-management/4-protect-api-infrastructure/images/multiple-plans-applied.png
deleted file mode 100644
index 73a12f3..0000000
Binary files a/api-management/4-protect-api-infrastructure/images/multiple-plans-applied.png and /dev/null differ
diff --git a/api-management/4-protect-api-infrastructure/manifests/admin-api.yaml b/api-management/4-protect-api-infrastructure/manifests/admin-api.yaml
deleted file mode 100644
index c4ac2f2..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/admin-api.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: protect-api-infrastructure-apimanagement-admin
- namespace: admin
-spec: {}
diff --git a/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess-ratelimit.yaml b/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess-ratelimit.yaml
deleted file mode 100644
index 15be9c7..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess-ratelimit.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: protect-api-infrastructure-apimanagement-admin-ratelimit
- namespace: admin
-spec:
- groups:
- - admin
- apis:
- - name: protect-api-infrastructure-apimanagement-admin
- apiPlan:
- name: admin
diff --git a/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess.yaml b/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess.yaml
deleted file mode 100644
index f761541..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/admin-apiaccess.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: protect-api-infrastructure-apimanagement-admin
- namespace: admin
-spec:
- groups:
- - admin
- apis:
- - name: protect-api-infrastructure-apimanagement-admin
diff --git a/api-management/4-protect-api-infrastructure/manifests/admin-apiplan.yaml b/api-management/4-protect-api-infrastructure/manifests/admin-apiplan.yaml
deleted file mode 100644
index 6ec3606..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/admin-apiplan.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: admin
- namespace: admin
-spec:
- title: "Admin Protection"
- description: "Admin API should not take more than one request per second."
- rateLimit:
- limit: 1
- period: 1s
diff --git a/api-management/4-protect-api-infrastructure/manifests/admin-ingressroute.yaml b/api-management/4-protect-api-infrastructure/manifests/admin-ingressroute.yaml
deleted file mode 100644
index 0b61592..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/admin-ingressroute.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: protect-api-infrastructure-apimanagement-admin
- namespace: admin
- annotations:
- hub.traefik.io/api: protect-api-infrastructure-apimanagement-admin
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.protect-infrastructure.apimanagement.docker.localhost`) && PathPrefix(`/admin`)
- kind: Rule
- services:
- - name: admin-app
- port: 3000
- middlewares:
- - name: stripprefix-admin
diff --git a/api-management/4-protect-api-infrastructure/manifests/api-bundle-access.yaml b/api-management/4-protect-api-infrastructure/manifests/api-bundle-access.yaml
deleted file mode 100644
index 6aa7658..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/api-bundle-access.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-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
diff --git a/api-management/4-protect-api-infrastructure/manifests/api-bundle.yaml b/api-management/4-protect-api-infrastructure/manifests/api-bundle.yaml
deleted file mode 100644
index bf487c6..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/api-bundle.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-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
diff --git a/api-management/4-protect-api-infrastructure/manifests/api-plan-for-bundle.yaml b/api-management/4-protect-api-infrastructure/manifests/api-plan-for-bundle.yaml
deleted file mode 100644
index 80b6da2..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/api-plan-for-bundle.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-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
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-api.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-api.yaml
deleted file mode 100644
index 7bf342a..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-api.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: protect-api-infrastructure-apimanagement-weather
- namespace: apps
- labels:
- subscription: standard
-spec:
- openApiSpec:
- path: /openapi.yaml
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota-premium.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota-premium.yaml
deleted file mode 100644
index 63fa800..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota-premium.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: protect-api-infrastructure-apimanagement-weather-quota
- namespace: apps
-spec:
- groups:
- - external
- apis:
- - name: protect-api-infrastructure-apimanagement-weather
- apiPlan:
- name: external-premium
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota.yaml
deleted file mode 100644
index 79e7da0..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess-quota.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: protect-api-infrastructure-apimanagement-weather-quota
- namespace: apps
-spec:
- groups:
- - external
- apis:
- - name: protect-api-infrastructure-apimanagement-weather
- apiPlan:
- name: external
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess.yaml
deleted file mode 100644
index 1c3cded..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-apiaccess.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIAccess
-metadata:
- name: protect-api-infrastructure-apimanagement-weather
- namespace: apps
-spec:
- groups:
- - external
- apis:
- - name: protect-api-infrastructure-apimanagement-weather
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-apiplan-premium.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-apiplan-premium.yaml
deleted file mode 100644
index 757ed8c..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-apiplan-premium.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: external-premium
- namespace: apps
-spec:
- title: "Premium Weather API Plan for external users"
- description: "Weather API should not take more than 500 requests in 24 hours"
- quota:
- limit: 500
- period: 24h
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-apiplan.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-apiplan.yaml
deleted file mode 100644
index 7f0d4b3..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-apiplan.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: APIPlan
-metadata:
- name: external
- namespace: apps
-spec:
- title: "Weather Protection for external users"
- description: "Weather API should not take more than 5 requests in 24 hours"
- quota:
- limit: 5
- period: 24h
diff --git a/api-management/4-protect-api-infrastructure/manifests/weather-ingressroute.yaml b/api-management/4-protect-api-infrastructure/manifests/weather-ingressroute.yaml
deleted file mode 100644
index a51b6f6..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/weather-ingressroute.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-apiVersion: traefik.io/v1alpha1
-kind: IngressRoute
-metadata:
- name: protect-api-infrastructure-apimanagement-weather
- namespace: apps
- annotations:
- hub.traefik.io/api: protect-api-infrastructure-apimanagement-weather
-spec:
- entryPoints:
- - web
- routes:
- - match: Host(`api.protect-infrastructure.apimanagement.docker.localhost`) && PathRegexp(`^/weather(/([0-9]+|openapi.yaml))?$`)
- kind: Rule
- services:
- - name: weather-app
- port: 3000
- middlewares:
- - name: stripprefix-weather
diff --git a/api-management/4-protect-api-infrastructure/manifests/whoami-api.yaml b/api-management/4-protect-api-infrastructure/manifests/whoami-api.yaml
deleted file mode 100644
index 8bd8c15..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/whoami-api.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-apiVersion: hub.traefik.io/v1alpha1
-kind: API
-metadata:
- name: protect-api-infrastructure-apimanagement-whoami
- namespace: apps
-spec: {}
diff --git a/api-management/4-protect-api-infrastructure/manifests/whoami-apiaccess.yaml b/api-management/4-protect-api-infrastructure/manifests/whoami-apiaccess.yaml
deleted file mode 100644
index bc23f41..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/whoami-apiaccess.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-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
diff --git a/api-management/4-protect-api-infrastructure/manifests/whoami-ingressroute.yaml b/api-management/4-protect-api-infrastructure/manifests/whoami-ingressroute.yaml
deleted file mode 100644
index 8ae68d3..0000000
--- a/api-management/4-protect-api-infrastructure/manifests/whoami-ingressroute.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-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
diff --git a/api-management/README.md b/api-management/README.md
new file mode 100644
index 0000000..bc35b98
--- /dev/null
+++ b/api-management/README.md
@@ -0,0 +1,3 @@
+# Traefik Hub API Management
+
+This section is coming soon. In the meantime, you can follow the [Traefik Hub API Management quick start guide](https://doc.traefik.io/traefik-hub/api-management/quick-start-guide) tutorial.