Redirects and rewrites

Redirects and rewrites

Deploy the sample services

Deploy httpbin

You will use the httpbin service to respond to requests.

$ kubectl create -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
        ports:
        - containerPort: 80
EOF

Deploy the httpbin service

$ kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin
EOF

Deploy a curl client

We will use curl to send requests to our httpbin service.

$ kubectl create -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      containers:
      - name: curl
        image: curlimages/curl
        command: ["/bin/sleep","3650d"]
        imagePullPolicy: IfNotPresent
EOF

Configure a redirect

You can use routes to return HTTP redirect (3xx) responses to a client.

Send a request to the service

$ kubectl exec deploy/curl -- curl -sSI http://httpbin:8000/anything/old-url

The httpbin service will show you the URL that you hit:

{
  "url": "http://httpbin:8000/anything/old-url"
}

Create a URL redirect route

$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-redirect
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: httpbin
    port: 8000
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /anything/old-url
      filters:
        - type: RequestRedirect
          requestRedirect:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /anything/new-url
            statusCode: 302
    - backendRefs:
      - name: httpbin
        port: 8000
EOF

Test the redirect

You will see that your request was sent a redirect:

$ kubectl exec deploy/curl -- curl -sSI http://httpbin:8000/anything/old-url
HTTP/1.1 302 Found
location: http://httpbin:8000/anything/new-url
date: Tue, 29 Oct 2024 23:51:35 GMT
server: istio-envoy
x-envoy-decorator-operation: http-filter-redirect-0-istio-autogenerated-k8s-gateway:8000/*
transfer-encoding: chunked

Note that there are two rules in this route. When a route is bound to a service, as in this case, it replaces the default behavior of the mesh to pass traffic directly to that service. Without explicitly defining the backendRef to fall through to, all traffic to httpbin that did not match the PathPrefix would receive a 404 error.

The first rule does not require a backendRef as a redirect is a terminal action.

To continue, delete the rule:

$ kubectl delete httproute http-filter-redirect

Configure a rewrite

You can also use a route to rewrite components of a request before it is sent to its destination.

Create a URL rewrite rule

$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-filter-rewrite
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: httpbin
    port: 8000
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /anything/old-url
      filters:
        - type: URLRewrite
          urlRewrite:
            hostname: httpbin
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /anything/new-url
      backendRefs:
        - name: httpbin
          port: 8000
    - backendRefs:
      - name: httpbin
        port: 8000
EOF

Test the rewrite

Test with curl. Requests to any path other than /anything/old-url are unchanged:

$ kubectl exec deploy/curl -- curl -sSi http://httpbin:8000/anything/unchanged/

Look for the URL served:

{
  "url": "http://httpbin:8000/anything/unchanged/"
}

Requests to /anything/old-url are rewritten to /anything/new-url:

$ kubectl exec deploy/curl -- curl -sSi http://httpbin:8000/anything/old-url/

Note both the new URL, and the header with the original path:

{
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin", 
    "User-Agent": "curl/8.7.1", 
    "X-Envoy-Original-Path": "/anything/old-url/"
  }, 
  "url": "http://httpbin/anything/new-url/"
}

To conclude, delete the rule:

$ kubectl delete httproute http-filter-rewrite

Cleaning up

Remove the routes, if you haven’t already:

$ kubectl delete httproute http-filter-redirect
$ kubectl delete httproute http-filter-rewrite

Delete httpbin and curl deployments and httpbin service:

$ kubectl delete deploy httpbin curl
$ kubectl delete svc httpbin