How to serve a static content using ingress nginx - nginx

I have one service called "workspace-service-b6" which is running on port 5000, See the below ingress file. Now I want to serve the static content on the same service (workspace-service-b6) by adding the path route.
Example:- Service is working on https://workspace-b6.dev.example.com
Now if the user adds "/workspace/v2/ "at the end of the URL.
Like this:- https://workspace-b6.dev.example.com/workspace/v2/ it will redirect to s3 bucket "https://s3.console/buckets/xyz/abc/build" where my static content is available.
My Ingress file :-
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: b6-ingress
namespace: b6
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/tls-acme: "true"
spec:
tls:
- hosts:
- workspace-b6.dev.example.com
secretName: xyz-crt
rules:
- host: workspace-b6.dev.example.com
http:
paths:
- backend:
serviceName: workspace-service-b6
service port: 5000

While it’s kind of possible, the real answer is “don’t”. The ingress system is just a proxy, set up separate pods for content.

Related

NGINX Ingress Routing based on Header

I have an nginx-ingress calling a custom auth-service before sending requests to the backend service, using this simple ConfigMap and Ingress:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
global-auth-url: auth-service-url:8080/authenticate
global-auth-method: GET
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
...
spec:
rules:
- host: host1
http:
paths:
- backend:
serviceName: backend-service
servicePort: 8080
Now I need something different.
How can I send requests, all with the same "Host" header, through different flows, one with auth-service and connected to backend-service1 and the other without any authentication and connecting to backend-service2?
To be clear, and using the custom header "Example-header: test"
If "Example-header" is "test", authenticate via my auth-service before sending to backend-service, as it's done now.
If "Example-header" is not defined, I want to send requests to a different backend service and do not use auth-service in the process.
I tried a couple of things, namely having 2 Ingresses, one with global-auth-url and the other with nginx.ingress.kubernetes.io/enable-global-auth: "false" but the auth-service is always called.
Can I do this with NGINX, or do I have to use Istio or Ambassador?
One way you can achieve this behavior is by abusing the canary feature.
For your backend-service, create a normal Ingress, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-backend
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 80
Create a second Ingress for you auth-service with enabled canary and set the header name and value, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-auth
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: Example-header
nginx.ingress.kubernetes.io/canary-by-header-value: test
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 80
Now, every request with Example-header: test routes to auth-service. Any other value, e. g. Example-header: some-value, will not route to auth-service but rather go to your backend-service.

GKE Nginx Ingress Controller Oauth2 Proxy redirect

I am trying to add authentication to my cluster by using an oauth2-proxy. Locally I tested and is working as expected: When I go to the landing page it redirects me to an IP such as GitHub. After login, I am redirected to my page and everything is working as expected. For some odd reason, when porting from local to the cluster living in the google cloud, I am not getting redirect to GitHub for authentication.
I have two ingresses, one for the oauth2-proxy (ingress-oauth2-proxy) and another for all of the apps (ingress-apps). I added the Nginx annotations and still nothing.
Here are the Ingress YAML file used for the creation of the ingress rules
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
acme.cert-manager.io/http01-edit-in-place: "true"
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/auth-url: "https://auth.example.com/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://auth.exmaple.com/oauth2/start?rd=$escaped_request_uri"
cert-manager.io/cluster-isuer: letsecnrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: $/1
name: ingress-apps
namespace: default
spec:
rules:
- host: echo.example.com
http:
paths:
- path: /
backend:
serviceName: echo1
servicePort: 80
tls:
- hosts:
- echo.exmaple.com
secretName: echo-tls-cert
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-oauth2-proxy
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
acme.cert-manager.io/http01-edit-in-place: "true"
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: auth.exmaple.com
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: 4180
path: /oauth2
tls:
- hosts:
- auth.exmaple.com
secretName: auth-tls-cert
I checked the logs of the OAuth proxy and when I go to echo.example.com nothing happens. If I make a request to auth.example.com/oauth2 I get redirected, as expected, to the IP login page which is GitHub in this case.
Am I missing something?
Note: I checked and both ingresses are being applied.
Ok, I figured it out: The problem was the Ingress controller used. I installed the Nginx controller from the repo helm.nginx.com/stable which is nginxinc and does not support the annotations. Therefore they were being ignored. To fix it I just used the kubernetes.github.io/ingress-nginx/deploy/#gce-gke. This is better explained here Nginx ingress controller authentication not working
Cheers ! :)

Kubernetes Nginx Ingress partial ssl termination

I'd like to split incoming traffic in Kubernetes Nginx in the following way:
Client --> Nginx --> {Service A, Service B}
The problem I am facing is Service A is an internal service and does not support HTTPS therefore SSL should be terminated for Service A. On the other hand, Service B is an external service (hosted on example.com) and only works over HTTPS.
I cannot manage to get this work easily with Kubernetes Nginx. Here is what I have come with:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-proxy
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/upstream-vhost: example.com
spec:
tls:
- hosts:
- proxy.com
secretName: secret
rules:
- host: proxy.com
http:
paths:
- path: /api/v1/endpoint
backend:
serviceName: service-a
servicePort: 8080
- path: /
backend:
serviceName: service-b
servicePort: 443
kind: Service
apiVersion: v1
metadata:
name: service-b
namespace: default
spec:
type: ExternalName
externalName: service-b.external
ports:
- port: 443
I have got a route for service-b.external:443 to point to example.com.
This solution only works if service-b is over HTTPS, but in my case, I cannot change to HTTPS for this service because of some other internal dependencies.
My problem is the backend-protocol annotation works for the whole kind and I cannot define it per path.
P.S: I am using AWS provider
Following the suggested solution and question from comments.
Yes, like mentioned below it is possible to have two ingress items. In your case
only one should have backend-protocol in it.
According to nginx ingress documentation:
Basic usage - host based routing¶
ingress-nginx can be used for many use cases, inside various cloud provider and supports a lot of configurations. In this section you can find a common usage scenario where a single load balancer powered by ingress-nginx will route traffic to 2 different HTTP backend services based on the host name.
First of all follow the instructions to install ingress-nginx. Then imagine that you need to expose 2 HTTP services already installed: myServiceA, myServiceB. Let's say that you want to expose the first at myServiceA.foo.org and the second at myServiceB.foo.org. One possible solution is to create two ingress resources:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myservicea
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myservicea.foo.org
http:
paths:
- path: /
backend:
serviceName: myservicea
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myserviceb
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myserviceb.foo.org
http:
paths:
- path: /
backend:
serviceName: myserviceb
servicePort: 80
When you apply this yaml, 2 ingress resources will be created managed by the ingress-nginx instance. Nginx is configured to automatically discover all ingress with the kubernetes.io/ingress.class: "nginx" annotation. Please note that the ingress resource should be placed inside the same namespace of the backend resource.
On many cloud providers ingress-nginx will also create the corresponding Load Balancer resource. All you have to do is get the external IP and add a DNS A record inside your DNS provider that point myServiceA.foo.org and myServiceB.foo.org to the nginx external IP. Get the external IP by running:
kubectl get services -n ingress-nginx
It is also possible to have separate nginx classes as mentioned here.

Hosting two web apps with nginx ingress in Kubernetes

I have a kubernetes cluster running in Azure Kubernetes Service (AKS). I've been following a series of workshops and I've set up an NGINX ingress controller. Right now I'm using nip.io in order to access my site. They had me create an ingress resource to expose the front end:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ratings-web-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: frontend.<redacted ip>.nip.io
http:
paths:
- backend:
serviceName: ratings-web
servicePort: 80
path: /
This works fine. I can brows the nip.io address and everything works right.
I wanted to extend this and create a separate site. I want it at the same address, just served at /foo
I tried to create an ingress resource:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: foo-web-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: frontend.<redacted ip>.nip.io
http:
paths:
- backend:
serviceName: foo-web
servicePort: 80
path: /foo
When I browse frontend.<redacted ip>.nip.io/foo I get a 404 not found from nginx.
I tried added the following annotation based on another SO post:
nginx.ingress.kubernetes.io/rewrite-target: /
Now when I browse /foo it responds, but all the content is blank. In the web app it's referencing everything at the root level like:
<link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
When it sees this path, I think it's going to the original website so I get strict MIME type errors or 404 errors.
What do I need to do to host two websites on the same nginx ingress controller at different paths?
Ingress controller will be confused when merging these two ingresses, what the correct order should be because more than one ingress resource is defined for same host.
Referring from docs you could use a single ingress resource as fanout.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: <redacted ip>.nip.io
http:
paths:
- path: /foo
backend:
serviceName: foo-web
servicePort: 80
- path: /bar
backend:
serviceName: bar-web
servicePort: 80

Kubernetes NGINX Ingress changes HTTP request from a POST to a GET

I'm using Kubernetes that is bundled with Docker-for-Mac. I'm trying to configure an Ingress that routes http requests starting with /v1/ to my backend service and /ui/ requests to my Angular app.
My issues seems to be that the HTTP method of the requests are changed by ingress (NGINX) from a POST to a GET.
I have tried various rewrite rules, but to no avail. I even switched from Docker-for-Mac to Minikube, but the result is the same.
If I use a simple ingress with no paths (just the default backend) then the service is getting the correct HTTP method.
The ingress below works:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
spec:
backend:
serviceName: backend
servicePort: 8080
But this ingress does not:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- http:
paths:
- path: /v1
backend:
serviceName: backend
servicePort: 8080
- path: /ui
backend:
serviceName: webui
servicePort: 80
When I debug the "backend" service I see that the HTTP Request is a GET instead of a POST.
I read somewhere that NGINX rewrites issue a 308 (permanent) redirect and the HTTP method is changed from a GET to a POST, but if that is the case how can I configure my ingress to support different paths for different services that require POST calls?
I found the solution to my problem. When I add host: to the configuration then the http method is not changed. Here is my current ingress yaml (the rewrite and regex are used to omit sending the /v1 as part of the backend URL)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: localhost
http:
paths:
- path: /v1(/|$)(.*)
backend:
serviceName: gateway
servicePort: 8080

Resources