Ingress SSL/TLS configuration with Cloudflare - nginx

I've created an ingress to serve my application, and configured it this way:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-api
namespace: api
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- api.mydomain.com
secretName: secret-tls
rules:
- host: api.mydomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: my-backend
servicePort: http
Being secret-tls one secret generated using this.
The problem is that I can use https if setting the SSL/TLS encryption mode to Flexible in Cloudflare (SSL/TLS -> Overview -> Flexible), but I get HTTP 525 when turning the SSL/TLS encryption mode to Full.
What can I do to fix this problem?

Related

Ingress rewrite to two different services from one DNS

I am trying to reach out to two services from my DNS.
Example:- myportal.com
myportal.com/app1
I have my SSO and SSL implementation on "myportal.com" and on the home page I have a button which calls a service "myportal.com/app1". I have tried multiple things but I am not able to configure both properly.
From below ingress config I am able to redirect to "myportal.com/app1" but its not working properly for "myportal.com". I have tried multiple thing including default backend and its not working for me. When I use default backend then "myportal.com" works but it stops redirecting to /app1.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myportal-ingress-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: portal-service
port:
number: 8097
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app-ui-service
port:
number: 8087
I am fairly new to kubernetes and I am not sure if it's the correct way to implement such things. I am open to new implementation too if it's using ingress and routing to different services using same dns on different path.
Thanks in advance for the help!
I was able to resolve this issue. The redirect in an ingress file would work for all the paths, so I created a separate ingress for each path with individual redirects.
Ingress 1 - myportal.com (with SSO and SSL)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/x-forwarded-prefix: /myportal-service
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
defaultBackend:
service:
name: myportal-service
port:
number: 80
rules:
- host: myportal.com
Ingress 2 - myportal.com/app1 (application deployed)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test-1
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app1-ui-service
port:
number: 8087
This helped me to resolve this issue. I also verified that this way is also a standard way and is provided in one of the documentation of nginx.
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/

CSRF cookie not set - possibly blocked by kubernetes ingress

I use Axios in React and Django Rest Framework with dj-rest-auth. After migrating from GCP to Azure and removing the unmaintained django-rest-auth, I got some new CSRF issues.
Initially I removed django-rest-auth and created my own LoginView from Django.contrib.auth.views. Noticed that this also gave the CSRF error in development. So I added dj-rest-auth, which solved my issue locally. Pushed to the AKS, but there the cookie still does not appear. I'm suspecting my ingress to be the problem, which is able to set INGRESSCOOKIE for both my backend and frontend, but no CSRF.
I know there's a million tickets about this topic, my Django settings are fine, the set-cookie resopnse header is set. Also use the right axios settings to make sure that if the cookie is there, it's used for requests. The problem is really with the fact that the set-cookie is not coming through, as it is being created in Django.
I use an Nginx controller with TLS on a static IP with and have my ingress defined as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.allow-http: "true"
spec:
tls:
- hosts:
- XXXXX
secretName: tls-secret
rules:
- host: XXXXXXXX
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api/
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080
The problems was indeed at the ingress, not so much with the settings, but with the routing. The routing used above, rewrites the targets to / for all requests. My backend actually has a page there, which is CSRF protected. It went to that page instead of the login page. Changing the ingress to below yielded better results.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: basic-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /$1
kubernetes.io/ingress.allow-http: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- XXXXXXXXXX
secretName: tls-secret
rules:
- host: XXXXXX
http:
paths:
- path: /?(.*)
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
- path: /api/?(.*)
pathType: Prefix
backend:
service:
name: backend
port:
number: 8080

Multiple Nginx Ingress configuration with same hostname annotations/TLS problem

I have an application accessed via hostA.com and a path '/' defined. This application needs annotations:
nginx.ingress.kubernetes.io/auth-tls-secret: ca1
nginx.ingress.kubernetes.io/auth-tls-verify-client: optional
Also, I need to access the same application via the same hostname on a special URL '/v8/something/abc' with https:// but without client authentication, so I need to remove the annotations for TLS. I tried with two different Ingress objects, but it doesn't work because the other Ingress is ignored. Merge does not work because it does not accept TLS annotations. Does anyone know how to configure this?
These below are my ingress objects:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-tls-secret: mynamespace/my-ca
nginx.ingress.kubernetes.io/auth-tls-verify-client: optional
name: ingressA
namespace: mynamespace
spec:
rules:
- host: hosta.com
http:
paths:
- backend:
serviceName: myservice
servicePort: http
path: /
tls:
- hosts:
- hosta.com
secretName: mysecret
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/auth-tls-verify-client: off
name: ingressB
namespace: mynamespace
spec:
rules:
- host: hosta.com
http:
paths:
- backend:
serviceName: myservice
servicePort: http
path: /v8/something/abc
tls:
- hosts:
- hosta.com
secretName: mysecret

nginx k8s ingress - forcing www AND https?

I have a kubernetes setup that looks like this:
nginx ingress -> load balancer -> nginx app
after getting an SSL certificate for www.foo.com, I've installed it in my nginx ingress as a secret, and it works as expected - traffic to www.foo.com gets redirected to the https version instead, and browsers display a secure connection indicator. Great.
What hasn't been easy, however, is getting the ingress to redirect non-www traffic to the www version of the site. I've tried using kubernetes.io/from-to-www-redirect: "true", but it doesn't seem to do anything - navigating to foo.com doesn't redirect me to the www version of the url, but either takes me to an insecure version of my site, or navigates me to default backend - 404 depending on whether i include foo.com as a host with it's own path in my ingress.
I have been able to set up a patchy redirect by adding the following to my actual application's nginx config -
server {
listen 80;
server_name foo.com;
return 301 http://www.foo.com$request_uri;
}
UPDATE: from-to-www-redirect DOES work; you just have to reference it with nginx.ingress.kubernetes.io rather than kubernetes.io as I was. But, this only works for foo.com - typing in https://foo.com explicitly causes browsers to display a security warning and no redirect to the proper URL of https://www.foo.com occurs.
Here's my current config for the nginx ingress itself:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
tls:
- hosts:
- www.foo.com
secretName: tls-secret
You need to add the certificate for the domain you want to be redirected:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-prod-front
servicePort: 80
path: /
tls:
- hosts:
- foo.com
- www.foo.com
secretName: tls-secret
I am not completely sure, whether from-to-www-redirect works with this setup, but you can replace it with the following lines, which do work:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($host = 'foo.com' ) {
rewrite ^ https://www.foo.com$request_uri permanent;
}
I have the following doing the job with the latest nginx-ingress 0.25.1:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-rule-web
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/from-to-www-redirect: 'true'
spec:
rules:
- host: foo.org
http:
paths:
- path: /
backend:
serviceName: web
servicePort: 80
tls:
- hosts:
- foo.org
- www.foo.org
secretName: letsencrypt-prod
I found the docs to be confusing here as well. Below is an example i have working. I believe you need to define the naked url in tls certs to avoid a cert error(your cert needs to be valid for both foo.com and www.foo.com). You CANNOT list the naked url under rules: hosts because that will get picked up prior to the redirect.
http://foo.com -> https://www.foo.com
https://foo.com -> https://www.foo.com
http://www.foo.com -> https://www.foo.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: foo-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.foo.com
http:
paths:
- backend:
serviceName: foo-frontend
servicePort: 80
path: /
tls:
- hosts:
- foo.com
- www.foo.com
secretName: tls-secret
This is rather a problem with your ssl certificate than the nginx ingress configuration. My guess is that your certificate is only valid for foo.com and not for www.foo.com. If you access www.foo.com your browser shows a security warning because the certificate isn't valid for the domain you are visiting.
I had to solve an issue first:
The solution that worked for me is the one from #demisx but on my first try, the solution was not working for another reason. I had more than one ingress with reference to the "example.com" root host and as described on the documentation this was omitting my www redirect rule.
Documentation refers that "If at some point a new Ingress is created with a host equal to one of the options (like domain.com) the annotation will be omitted."
This is example is wrong:
Ingress 1 - to handle example.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example-frontend
servicePort: 80
path: /
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Ingress 2 - to handle example.com/news
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress-news
spec:
rules:
- host: example.com. # <--------- I HAD ANOTHER REFERENCE
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
- host: www.example.com
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Solution - Correct Configuration
Make sure that you don't have any other ingress created with the root domain otherwise the redirect will not work as documentation refers. I removed the reference to example.com host on ingress 2 and then immediately started to work.
Ingress 1 - to handle example.com
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: example-frontend
servicePort: 80
path: /
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Ingress 2 - to handle example.com/news
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-https-ingress-news
spec:
rules:
# <--------- removed the other reference to the root host
- host: www.example.com
http:
paths:
- backend:
serviceName: example-news
servicePort: 80
path: /news
tls:
- hosts:
- example.com
- www.example.com
secretName: tls-secret
Note: By the way, I didn't need to add the forward annotation to the 2nd ingress cause is already handled by the first ingress. I'm not sure though, if the order of deployment matters for nginx ingress controllers so take this as a note only and try to confirm yourself.

ingress configuration for dashboard

I did nginx ingress controller tutorial from github and
exposed kubernetes dashboard
kubernetes-dashboard NodePort 10.233.53.77 <none> 443:31925/TCP 20d
created ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/ssl-passthrough: "true"
nginx.org/ssl-backends: "kubernetes-dashboard"
kubernetes.io/ingress.allow-http: "false"
name: dashboard-ingress
namespace: kube-system
spec:
tls:
- hosts:
- serverdnsname
secretName: kubernetes-dashboard-certs
rules:
- host: serverdnsname
http:
paths:
- path: /dashboard
backend:
serviceName: kubernetes-dashboard
servicePort: 443
ingress-nginx ingress-nginx NodePort 10.233.21.200 <none> 80:30827/TCP,443:32536/TCP 5h
https://serverdnsname:32536/dashboard
but dashboard throws error
2018/01/18 14:42:51 http: TLS handshake error from ipWhichEndsWith.77:52686: tls: first record does not look like a TLS handshake
and ingress controller logs
2018/01/18 14:42:51 [error] 864#864: *37 upstream sent no valid HTTP/1.0 header while reading response header from upstream, client: 10.233.82.1, server: serverdnsname, request: "GET /dashboard HTTP/2.0", upstream: "http://ipWhichEndsWith.249:8443/dashboard", host: "serverdnsname:32536"
10.233.82.1 - [10.233.82.1] - - [18/Jan/2018:14:42:51 +0000] "GET /dashboard HTTP/2.0" 009 7 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 OPR/49.0.2725.64" 25 0.001 [kube-system-kubernetes-dashboard-443] ipWhichEndsWith.249:8443 7 0.001 200
On my mind it is related with nginx redirection to upstream: "http://ipWhichEndsWith.249:8443/dashboard" .
tried to update controller image version to 0.9.0-beta.19 - didnt help
Thank you for any help.
As you pointed out, looks like nginx is proxying your https request to ipWhichEndsWith.249:8443, which is an HTTPS endpoint, using http as protocol.
You should add the following annotation to your PodSpec:
LATEST
This annotation was added to replace the deprecated annotation since 0.18.0
#2871 Add support for AJP protocol
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
DEPRECATED
This annotation was deprecated in 0.18.0 and removed after the release of
0.20.0
#3203 Remove annotations grpc-backend and secure-backend already deprecated
nginx.ingress.kubernetes.io/secure-backends: "true"
This should make nginx forward your request to the pods with https.
Source: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md#backend-protocol
Docs: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#backend-protocol
Just for code reference. There are 2 gtochas. Setting the proper annotations since the dashboard talks https and using the correct namepace for the ingress. tls config is optional.
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: dashboard-google
namespace: kube-system
annotations:
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
tls:
- hosts:
- kube.mydomain.com
secretName: tls-secret
rules:
- host: kube.mydomain.com
http:
paths:
- path: /
backend:
serviceName: kubernetes-dashboard
servicePort: 443
To keep this ticket updated (if user uses nginx ingress) in order to reach the Kubernetes Dashboard you need to apply the following annotations:
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
Do not use secure-backends on later versions than image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1. It is replaced by backend-protocol.
If the user is using ingress in non https port e.g. 80 can be done as documented here TLS termination (nging ingress documentation).
Sample of complete code with subdomain:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard-ingress
namespace: kubernetes-dashboard
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
tls:
- hosts:
- "dashboard.my.example.com"
secretName: kubernetes-dashboard-secret
rules:
- host: "dashboard.my.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443
Hope this help other beginners like me not to spend so much time to figure out how to do it. Also the user should take in consideration the external load balancer configuration towards the ingress controller. Remember to set it up as SSL Pass-Through for the port that you will be forwarding.
Update: In case the user wants to use another ingress provider e.g. Kubernetes Ingress Controller Documentation/HAProxy Kubernetes Ingress/Controller 1.4
Sample of code with annotations:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard-ingress
namespace: kubernetes-dashboard
annotations:
haproxy.org/server-ssl: "true"
spec:
tls:
- hosts:
- "dashboard.my.example.com"
secretName: kubernetes-dashboard-secret
rules:
- host: "dashboard.my.example.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443
The user should not forget that the secrets are unique per namespace.
You could also use the helm charts available here
helm-chart/kubernetes-dashboard
Then setup your values.yaml file in order to override ingress parts like enable it, and adding hosts are available.
Here is an ingress for the dashboard that works for me.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard
namespace: kube-system
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/dashboard)$ $1/ redirect;
spec:
ingressClassName: nginx
tls:
- hosts:
- yourdomain.com
secretName: kubernetes-dashboard-tls
rules:
- host: yourdomain.com
http:
paths:
- path: /dashboard(/|$)(.*)
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443

Resources