How to redirect with envoy proxy - http-redirect

We use envoy proxy as an ingress HTTP proxy. Now we would like to have a redirect from https:/our_domain/ to https:/our_domain/static/index.html.
All our attempts failed so far, for example
routes:
- match:
path: "/"
redirect: { path_redirect: "/static/index.html" }
- match:
prefix: "/"
route:
prefix_rewrite: "/"
cluster: our_cluster
How to configure routing for this use case? Please no Lua solution.

The problem was that the envoy proxy is behind a tls-terminating proxy. The redirect is therefore always with a http scheme, which is not served by the tls-terminating proxy.
The solution is
https_redirect
(bool) The scheme portion of the URL will be swapped with “https”.
The correct routing must thus be
routes:
- match:
path: "/"
redirect:
https_redirect: true
path_redirect: "/static/index.html"
- match:
prefix: "/"
route:
cluster: our_cluster

Prefix “/“ matches any request so you just redirect endlessly. Set up a route that matches prefix “/static” in front of the catch all one and forward to it to an upstream cluster to provide a response. (For static files you could also serve them directly from Envoy.)

- name: listener_http
address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type : auto
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
redirect:
path_redirect: "/"
https_redirect: true
http_filters:
- name: envoy.router
config: {}
put this code before your listerner of https section to redirect all request

Related

k8s ingress path match not working as expected

According to nginx path match policy: https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
Path Priority¶
In NGINX, regular expressions follow a first match policy. In order to enable more accurate path matching, ingress-nginx first orders the paths by descending length before writing them to the NGINX template as location blocks.
My rules are defined like this:
spec:
ingressClassName: some-lb
rules:
- host: "example.com"
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: cs-stage-backend
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: cs-stage-frontend
port:
number: 80
So, according to the path rule, if I go to example.com/api/v1/docs it should go to cs-stage-backend and rest all go to cs-stage-frontend. But it always goes to cs-stage-frontend.
Can anyone please help me if I am missing something?

Nginx Ingress path is not pointing to service / path

I have nginx ingress installed on my cluster. Here is the yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-client
annotations:
kubernetes.io/ingress.class: nginx
namespace: dev
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: client-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
When I hit / prefix it is good.
curl http://example.com (All Good)
Problem:
But when I hit / api prefix, it returns /api of the service not / of the service
curl http://example.com/api (It should link to api-service, but it is linking to api-service/api)
Any help will be appreciated!
This is because a path / with type Prefix will match / and everything after, including /api. So your first rule overshadows the second rule in some sense.
I don't know if it's an option for you, but it would be probably most elegant and idiomatic to use different hostnames for both services. If you deploy cert-manager, this shouldn't be a problem.
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: client-service
port:
number: 80
# use a different hostname for the api
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
Another option could be to use regex in your frontend path rule. And let it not match when the slash is followed by api. For that, you need to set an annotation.
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
Then you can do something like the below for your frontend service. Using a negative lookahead.
- path: /(?!api).*
Alternatively, but less pretty, you could add a path prefix to your frontend service and strip it away via path rewrite annotation. But then you may have to write two separate ingress manifests as this is annotation counts for both, or you need to use a more complex path rewrite rule.
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
- path: /ui(/|$)(.*)
Perhaps it's also sufficient to move the more specific route, /api, before the generic / route. In that case, switch the path around in the list. If they end up in that order in the nginx config, nginx should be able to handle it as desired.
You could use nginx.ingress.kubernetes.io/rewrite-target:
In some scenarios the exposed URL in the backend service differs from the specified path in the Ingress rule. Without a rewrite any request will return 404. Set the annotation nginx.ingress.kubernetes.io/rewrite-target to the path expected by the service.
So, here you could change your ingress as next:
metadata:
name: ingress-client
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
namespace: dev
The ingress definition above will result in the following rewrites:
api-service/api rewrites to api-service/

Istio VirtualService - broken URLs

Help!
I am using Istio to setup a service mesh in Kubernetes. The Virtual Service definition routes the traffic to the desired service:
(...)
http:
- match:
- uri:
prefix: /drill/
rewrite:
uri: /
route:
- destination:
host: drill-service.drill.svc.cluster.local
port:
number: 8047
However, when calling the entrypoint
https://<HOST>:<NODEPORT_INGRESS_GW>/drill
I do see the HTML page, but the URLs are broken and CSS sheets are not loaded correctly. Reason is that the HTML source code points to the wrong targets:
li>Storage</li>
instead of
li>Storage</li>
How can I fix this problem?
Thanks,
Matt
When you use rewrite you need to add path in virtual service for your dependencies like css and js.
The whole process with rewrite and how it should be configured was well explained by #Rinor here.
This Istio in practise tutorial also explains it well.
Let’s break down the requests that should be routed to Frontend:
Exact path / should be routed to Frontend to get the Index.html
Prefix path /static/* should be routed to Frontend to get any static files needed by the frontend, like Cascading Style Sheets and JavaScript files.
Paths matching the regex ^.*.(ico|png|jpg)$ should be routed to Frontend as it is an image, that the page needs to show.
http:
- match:
- uri:
exact: /
- uri:
exact: /callback
- uri:
prefix: /static
- uri:
regex: '^.*\.(ico|png|jpg)$'
route:
- destination:
host: frontend
port:
number: 80
Additionally you can take a look here.
EDIT
Why your example does not work
With your current virtual service your requests will be as follows:
http://www.page.com/drill/
Rewritten: http://www.page.com/
http://www.page.com/drill/storage
Rewritten: http://www.page.com/storage
So now you would have to either change virtual service configuration, for example for paths without rewrite or change your app dependencies location, so istio could actually see /drill/storage path with your current virtual service, for now it see /storage path , and there is nothing here as the real path is /drill/storage.
http:
- match:
- uri:
prefix: /
- uri:
prefix: /drill/storage/
- uri:
prefix: /...
What I would suggest
If you have your domain configured as a virtual service host you might try with this virtual service:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: istio-vs
spec:
hosts:
- "drill.domain.com"
gateways:
- gateway
http:
- match:
- uri:
prefix: /
rewrite:
uri: /drill/
route:
- destination:
host: drill-service.drill.svc.cluster.local
port:
number: 8047
With this virtual service your requests will be as follows:
http://www.page.com/
Rewritten: http://www.page.com/drill/
http://www.page.com/storage
Rewritten: http://www.page.com/drill/storage

Envoy Proxy with Docker for grpc-web. Using ssl results in ERR_CERT_COMMON_NAME_INVALID on browser

I am trying to configure my envoy proxy to allow for save requests from my angular application to my application server using grpc. I have a letsencrypt certificate loaded, but the requests fail and chrome prints a: ERR_CERT_COMMON_NAME_INVALID when trying to connect. I have an apache2 running serving my web application. The envoy proxy on docker and the web application are running on the same machine.
my envoy.yaml:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 17887 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
stream_idle_timeout: 0s
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["myactualdomain.com"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: grpc-status,grpc-message
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
tls_context:
common_tls_context:
alpn_protocols: "h2"
tls_certificates:
- certificate_chain: { filename: "/etc/fullchain.pem" }
private_key: { filename: "/etc/privkey.pem" }
clusters:
- name: greeter_service
connect_timeout: 1.00s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts: [{ socket_address: { address: localhost, port_value: 17888 }}]
I was thinking i might be because I am not using the traditional https port.
Any help appreciated.
I actually got it working. First of all I added a new subdomain for the envoy proxy and created a new pair of certificates. Also don't do this: domains: ["myactualdomain.com"] but rather ["*"] as this leads to a CORS violation. If you only connect with grpc-web and the envoy don't use ssl as they run on the same machine anyway. If you wan't to do that though, you might want to take a look at that: https://medium.com/#farcaller/how-to-configure-https-backends-in-envoy-b446727b2eb3, I didn't try it though.

How to host multiple applications in one Istio service mesh?

I'm setting up an Istio service mesh with two services inside both running a Graphql engine. I'm planning to set them on two different subpaths. How would you set up redirection on VirtualService?
I already tried using this VirtualService config
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: hasura-1
spec:
hosts:
- "*"
gateways:
- hasura-gateway
http:
- match:
- uri:
prefix: /hasura1
route:
- destination:
host: hasura-1
port:
number: 80
- match:
- uri:
prefix: /hasura2
route:
- destination:
host: hasura-2
port:
number: 80
but I keep on having error 404 whenever I try accessing these prefixes.
EDIT: I've updated my virtual service to incorporate rewrite.uri. Whenever I try accessing either prefixes I get redirected to / and it gives out an error 404. Here is my updated Gateway and VirtualService manifest.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: hasura-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: hasura-1
spec:
hosts:
- "*"
gateways:
- hasura-gateway
http:
- match:
- uri:
exact: /hasura1
rewrite:
uri: /
route:
- destination:
host: hasura-1
port:
number: 80
- match:
- uri:
exact: /hasura2
rewrite:
uri: /
route:
- destination:
host: hasura-2
port:
number: 80
---
On what path your Hasura's GraphQL endpoint is configured?
The way your VirtualService is configured, a request to your gateway will behave like this:
my.host.com/hasura1 --> hasura-1/hasura1
my.host.com/hasura1/anotherpath --> hasura-1/hasura1/anotherpath
my.host.com/hasura2 --> hasura-2/hasura2
Maybe you are missing a rewrite.uri rule to strip the path from the request.
e.g.: With this rule:
http:
- match:
- uri:
prefix: /hasura1
rewrite:
uri: /
route:
- destination:
host: hasura-1
port:
number: 80
your Hasura container should receive the requests on the root path:
my.host.com/hasura1 --> hasura-1/
my.host.com/hasura1/anotherpath --> hasura-1/anotherpath

Resources