This question already has answers here:
How to force SSL for Kubernetes Ingress on GKE
(10 answers)
Closed 3 years ago.
I have Nginx-based service which configured to accept HTTPS-only.
However GKE ingress answers HTTP requests in HTTP. I know that GKE Ingress doesn't know to enforce HTTP -> HTTPS redirect, but is it possible to learn it at least return HTTPS from service?
rules:
- http:
paths:
- path: /*
backend:
serviceName: dashboard-ui
servicePort: 8443
UPDATE: I do have TSL configured on GKE ingress and my K8S service. When request comes in HTTPS everything works nice. But HTTP requests gets HTTP response. I implemented HTTP->HTTPS redirect in my service, but it didn't help. In fact, for now all communication between ingress and my service is HTTTPS because service exposes only HTTPS port
SOLUTION - thanks to Paul Annetts: Nginx should check original protocol inside HTTPS block and redirect, like this
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
Yes, you can configure the GKE Kubernetes Ingress to both terminate HTTPS for external traffic, and also to use HTTPS internally between Google HTTP(S) Load Balancer and your service inside the GKE cluster.
This is documented here, but it is fairly complex.
For HTTPS to work you will need a TLS certificate and key.
If you have your own TLS certificate and key in the cluster as a secret, you can provide it using the tls section of Ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress-2
spec:
tls:
- secretName: my-secret
rules:
- http:
paths:
- path: /*
backend:
serviceName: my-metrics
servicePort: 60000
You can also upload your TLS certificate and key directly to Google Cloud and provide a ingress.gcp.kubernetes.io/pre-shared-cert annotation that tells GKE Ingress to use it.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-psc-ingress
annotations:
ingress.gcp.kubernetes.io/pre-shared-cert: "my-domain-tls-cert"
...
To use HTTPS for traffic inside Google Cloud, from the Load Balancer to your GKE cluster, you need the cloud.google.com/app-protocols: '{"my-https-port":"HTTPS","my-http-port":"HTTP"}' annotation on your NodePort service. Note that your ports must be named for the HTTPS to work.
apiVersion: v1
kind: Service
metadata:
name: my-service-3
annotations:
cloud.google.com/app-protocols: '{"my-https-port":"HTTPS","my-http-port":"HTTP"}'
spec:
type: NodePort
selector:
app: metrics
department: sales
ports:
- name: my-https-port
port: 443
targetPort: 8443
- name: my-http-port
port: 80
targetPort: 50001
The load balancer itself doesn’t support redirection from HTTP->HTTPS, you need to find another way for that.
As you have NGINX as entry-point into your cluster, you can detect the protocol used to connect to the load-balancer with the X-forwarded-Proto HTTP header and do a redirect, something like this.
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
Related
I was reading about ingress controller and ingress resource to route the incoming request to Kubernetes cluster to specific service.
Ingress resource file will be similar to:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myservicea
spec:
rules:
- host: myservicea.foo.org
http:
paths:
- path: /v1/myapp/health
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
ingressClassName: nginx
My understanding from above ingress is, all incoming request(url like: https://myservicea.foo.org/v1/myapp/health) to ingress controller will be redirected to the service "myservice" on port 80. No matter request is coming from which domain(app, client, host, IP or localhost).
Here my question is, How can we add rules in ingress resource to specify, request coming from specific domain(app, client, host or IP) will be routed to specific service("myservice") based on path. If it is coming from any other domain, request will be simply discarded.
What example you have shared above is host-based routing. Where you have a different Host or Domain and based on traffic gets forwarded to service. example.com
you can also do the path-based routing with an ingress controller where regex might be used. /v1/myapp
Ingress controller if you are using the nginx you won't be able to route based on IP address. You can whitelist the IPs addresses, only certain IP can access the Ingress else will be blocked but based on IP you can not forward request to service.
However there is always way around so if you are already have Nginx config you can also do same in ingress also.
You have to try and test a few blocks based on that you might be able to achieve what you are looking for.
You can leverage the server-snippet or configuration-snippet to create the blocks.
For example if /preview 302 redirect it
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite /preview https://test.app.example.com$uri permanent;
Another example based on server_name same you can check for header values and based on that you can do routing.
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-snippet: |
server_name ~^(?<subdomain>\w+)\.example\.io$;
nginx.ingress.kubernetes.io/rewrite-target: /proxy/$subdomain/$1
name: nginx-forward
spec:
rules:
- http:
paths:
- backend:
service:
name: service
port:
number: 8080
path: /(.*)
pathType: Prefix
Considering here nginx ingress controller here you can setup different CRDs also from the opensource project or install plugins if using Kongs baed on the requirement.
Read more server-snippet : https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#server-snippet
Read more configuration-snippet : https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#configuration-snippet
I'm trying to make the kubernetes dashboard externally accessible.
For this i installed nginx-ingress as ingress controller in my kubernetes cluster which is accessible on port 32012 on the kubernetes node IP.
Now i want to make it accessible via a domain like k8s.xxx.xx. For that I'd create a TLS certificate from Lets Encrypt to secure the whole thing via HTTPS.
Now we have a Apache2 reverse proxy which handles the requests going to k8s.xxx.xx and proxies them to port 32012, but here I'm getting a error from nginx-ingress:
The plain HTTP request was sent to HTTPS port
The connection chain is:
User -> https://k8s.xxx.xx/ > Apache2 reverse proxy redirecting to port 32012 on kubernetes node and handles Lets Encrypt certificate > ingress controller > kubernetes-dashboard pod.
My kubernetes ingress component looks like the following:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard-ingress
namespace: kubernetes-dashboard
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: k8s.xxx.xx
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443
It seems to listen on 80 by default - sensible - but if I wanted it to listen for requests on (for example) 8000, how would I specify this?
For clarity, this is via the nginx controller enabled via minikube addons enable ingress)
Ingress exposes HTTP and HTTPS routes from outside the cluster to
services
within the cluster.
It means that it'll use default ports for HTTP and HTTPS ports.
From the documentation we can read:
An Ingress does not expose arbitrary ports or protocols. Exposing services other than HTTP and HTTPS to the internet typically uses a service of type Service.Type=NodePort or Service.Type=LoadBalancer.
While in general, Ingress does not allow you to expose random things on random ports, in case of nginx-ingress, you can do it. But you have to use additional annotation.
For instance, if your pod exposes 443, but you want it to be available on port 8081 you have to do following trick:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myservice
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: nginx
nginx.org/listen-ports-ssl: "8081"
spec:
tls:
- hosts:
- host.org
secretName: my-host-tls-cert
rules:
- host: host.org
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 443
nginx-ingress controller actually allows changing http and https ports.
See the configuration parameters:
controller.service.ports.http
controller.service.ports.https
I have a service (Node REST app, let's call it ABC) within the cluster. This app listens to two ports, one runs on HTTP and the other on HTTPS.
I use Ingress. I can see Ingress only use HTTP port to communicate with ABC. I got confirmed this by stopping the HTTP and running ABC on HTTPS only.
Do I have to make any specific setup in Ingress so to use HTTPS instead of HTTP to communicate with ABC? Or is it a pattern to run services within a cluster on HTTP when use Ingress?
Ingress yaml :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: abc.containers.myhost.net
http:
paths:
- backend:
serviceName: my-test-node
servicePort: 9080
path: my-test-node/xyz
tls:
- hosts:
- abc.containers.myhost.net
secretName: abc1
I want to expose a HTTP service running in Google Container Engine over HTTPS only load balancer.
How to define in ingress object that I want HTTPS only load balancer instead of default HTTP?
Or is there a way to permanently drop HTTP protocol from created load balancer? When I add HTTPS protocol and then drop HTTP protocol, HTTP is recreated after few minutes by the platform.
Ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myapp-ingress
spec:
backend:
serviceName: myapp-service
servicePort: 8080
In order to have HTTPs service exposed only, you can block traffic on port 80 as mentioned on this link:
You can block traffic on :80 through an annotation. You might want to do this if all your clients are only going to hit the loadbalancer through https and you don't want to waste the extra GCE forwarding rule, eg:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
annotations:
kubernetes.io/ingress.allow-http: "false"
spec:
tls:
# This assumes tls-secret exists.
# To generate it run the make in this directory.
- secretName: tls-secret
backend:
serviceName: echoheaders-https
servicePort: 80
You could also use FrontendConfig
HTTP to HTTPS redirects are configured using the redirectToHttps field
in a FrontendConfig custom resource. Redirects are enabled for the
entire Ingress resource so all services referenced by the Ingress will
have HTTPS redirects enabled.
The following FrontendConfig manifest enables HTTP to HTTPS redirects.
Set the spec.redirectToHttps.enabled field to true to enable HTTPS
redirects. The spec.responseCodeName field is optional. If it's
omitted a 301 Moved Permanently redirect is used.
For example
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
name: your-frontend-config-name
spec:
redirectToHttps:
enabled: true
responseCodeName: MOVED_PERMANENTLY_DEFAULT
MOVED_PERMANENTLY_DEFAULT is on of the available RESPONSE_CODE field value, to return a 301 redirect response code (default if responseCodeName is unspecified).
You can find more options here: HTTP to HTTPS redirects
Then you have to link your FrontendConfig to the Ingress, like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: your-ingress-name
annotations:
networking.gke.io/v1beta1.FrontendConfig: your-frontend-config-name
spec:
tls:
...