2

Question

I would like to know how to configure the Nginx Ingress controller to redirect to a URL when calling the external IP address.

Ingress controller yaml

apiVersion: v1
kind: Service
metadata:
labels:
  helm.sh/chart: ingress-nginx-3.4.1
  app.kubernetes.io/name: ingress-nginx
  app.kubernetes.io/instance: ingress-nginx
  app.kubernetes.io/version: 0.40.2
  app.kubernetes.io/managed-by: Helm
  app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: NodePort
ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: http
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
externalIPs: 
- ip1
- ip2
- ip3
selector:
  app.kubernetes.io/name: ingress-nginx
  app.kubernetes.io/instance: ingress-nginx
  app.kubernetes.io/component: controller

If I enter my external IP into the browser I will of course end up on the Nginx 404 page. In this special case, I would like to set up a redirection to its specific domain e.g. google.com. I would like to increase the security of the public K8s cluster. I have not yet configured this particular case and would like to know if it is even possible to set up such a forwarding process. All configured Ingress resources released their service to the internet.

ZPascal
  • 23
  • 1
  • 6
  • Hi, Can you please provide some more information about your case? What is goal here? What you tried so far (some ingress, deployments config examples)? What where your are sending requests towards ingress (external or internal)? Having all of those in formations placed in question will help also other with similar goals, issues. – acid_fuji Oct 26 '20 at 09:37
  • 1
    @thomas I update the main post. – ZPascal Oct 26 '20 at 22:08
  • Thanks @ZPascal. I will prepare an answer for you. – acid_fuji Oct 27 '20 at 14:13

2 Answers2

2

Bare-metal environments lacks the commodity that traditional cloud environments provide where network load balancers are available and single K8s manifest is enough to provide single point of contact to the NGINX ingress controller. Of course we have to remember that internal redirect follows the ingress resource which then configures the ingress controller accordingly.

With External IP method the source IP of HTTP is not preserved therefore not recommended to use it despite it's apparent simplicity. So you will loose the information what is going with your requests (unless you will montor ingress controller)

To answer the question how to configure external IP redirect inside Nginx Ingress Controller we have to start from knowing what ingress actually is:

Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource. There must be an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect.

To achieve expected results you should create two separate ingress objects (not controllers). First one with no host is specified so the rule applies to all inbound HTTP traffic through the IP address specified as described in the Ingress rules:

apiVersion: extensions/v1beta1
kind: Ingress
metadata: 
  annotations: 
    nginx.ingress.kubernetes.io/permanent-redirect: "https://www.google.com"
  name: ingress-redirect
spec: 
  rules: 
  - http: 
      paths: 
      - path: / 
        pathType: Prefix 
        backend: 
          serviceName: example
          servicePort: 12 

And the second ingress object with a host that is provided (for example, hello-world.info, so that the rules apply to that host. Like in the example below:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-host
spec: 
  rules: 
  - host: hello-world.info
    http: 
     paths: 
     - path: / 
       pathType: Prefix  
       backend: 
        serviceName: web
        servicePort: 80

As you can see below, the above configuration creates the following sections in the nginx-ingress-controller's nginx.conf. One is responsible for serving requests with specific Host: header, another is for serving requests w/o Host: header e.g. if request is sent to IP address directly:

enter http { 

# works when no Host header is provided

    ## start server _
    server {
            server_name _ ;

            listen 80 default_server reuseport backlog=511 ;
            listen 443 default_server reuseport backlog=511 ssl http2 ;

            location / {


                    set $namespace      "default";
                    set $ingress_name   "ingress-redirect";
                    set $service_name   "";
                    set $service_port   "";
                    set $location_path  "/";

                    return 301 https://www.google.com;


# works when specific Host header is provided

    ## start server hello-world.info
    server {
            server_name hello-world.info ;

            listen 80  ;
            listen 443  ssl http2 ;


            location / {

                    set $namespace      "default";
                    set $ingress_name   "ingress-host";
                    set $service_name   "web";
                    set $service_port   "80";
                    set $location_path  "/";

            }

    }
    ## end server hello-world.info

For testing purposes I have deployed quickly those two ingress objects and nginx pod:

➜ kubectl run --image nginx web   

And expose it to have serivce behind the second ingress object:

➜ kubectl expose pod web --port 80 

As you can see when curling the redirect works as expected:

➜  ~ curl $(minikube ip)  -I                            
HTTP/1.1 301 Moved Permanently
Server: nginx/1.19.0
Date: Tue, 27 Oct 2020 13:22:06 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://www.google.com

And if you curl the same address with the host name it redirects towards nginx pod:

➜  ~ curl $(minikube ip) -H "Host: hello-world.info"    
---
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
---

Also it is worth to mention about Kubernetes docs that provide also good example of Name based virtual hosting. It supports routing HTTP traffic to multiple host names at the same IP address. The example in the document tells the backing load balancer to route requests based on the Host header.

For example the Ingress mentioned in the documentation page above routes traffic requested for first.bar.com to service1, second.foo.comto service2, and any traffic to the IP address without a hostname defined in request (that is, without a request header being presented) to service3.

acid_fuji
  • 533
  • 3
  • 8
  • 1
    Thank you for your detailed answer. I already set the "normal" Ingress to the DNS entry. With your answer I was able to set the entry for the external IP address correctly. – ZPascal Oct 29 '20 at 08:07
0

Hej there, have a look at "default backend": https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#default-backend

This annotation is of the form nginx.ingress.kubernetes.io/default-backend: to specify a custom default backend. This is a reference to a service inside of the same namespace in which you are applying this annotation. This annotation overrides the global default backend.

Off-Topic: To increase security i hide my IPs (ingress-nginx) behind cloudflares network. I just allow the cloudflare IPs to connect to my webservers via script. An exmaple for a standalone host: https://raw.githubusercontent.com/cloudpanel-io/scripts/master/cloudflare/whitelist_ips

Pros:

  • noone knows my real IP
  • User can just connect via "real" DNS Records

Cons:

  • you have to use Cloudflare (free Plan available)
  • higherTTFB

PS: i have nothing todo with cloudflare, neither work for them

Berndinox
  • 240
  • 1
  • 3
  • 11