Kubernetes HTTPS Ingress in Google Container Engine - kubernetes

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:
...

Related

Does ExternalName service act as a reverse proxy?

I have the following need:
There is API that may be accessed only from allowlisted IPs. I'd like to make this API available publicly.
I thought about the following solution:
Create a service of type ServiceName:
kind: Service
apiVersion: v1
metadata:
name: my-svc
spec:
type: ExternalName
externalName: restricted-api.com
Create an ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- mysite.com
secretName: mysite-tls
rules:
- host: example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: my-svc
port:
name: https
Is my understanding correct that with such a setup when I call https://example.com/request on K8s level the request will be sent to https://restricted-api.com/request? The caller would not know that there is communication with restricted-api.com. Since the clients' IPs are dynamic the restricted-api.com would not allow them to call it.
The k8s IP is static and I could allowlist it.
Ok, if these are just your thoughts, I would recommend to look into this annotation:
externalTrafficPolicy=local is an annotation on the Kubernetes service resource that can be set to preserve the client source IP. When this value is set, the actual IP address of a client (e.g., a browser or mobile application) is propagated to the Kubernetes service instead of the IP address of the node.
For more information you can find here or in official Kubernetes docs.
Feel free to reach me out again, if you start to realize your thoughts and will face any issue with this.

K8s Ingress to Static Assets in DigitalOcean Bucket

I'm trying to use an Ingress and ExternalName Service in Kubernetes to route traffic to an external storage service (DigitalOcean Spaces) - but no matter what I try, I get some form of http error.
Things I've tried:
https://github.com/kubernetes/ingress-nginx/pull/629#issue-116679227 (Error: 404 Not Found, nginx)
https://github.com/kubernetes/ingress-nginx/issues/1809 (Error: 502 Bad Gateway, nginx)
A fair bit of other tinkering which has been lost to time.
How do I configure a K8s Ingress/Service to direct ingress requests from example.com/static to a storage bucket (e.g. <zone>.digitaloceanspaces.com/<bucket-name>/<path>/<object>)?
It looks like some of the resources I was able to find were simply outdated. The following solution works as of Kubernetes v1.21.4.
Important Notes:
All Ingress annotations are required:
kubernetes.io/ingress.class: nginx - necessary to engage Nginx ingress controller.
nginx.ingress.kubernetes.io/backend-protocol: HTTPS - necessary to maintain HTTPS traffic to service (this replaces /secure-backends in older versions).
nginx.ingress.kubernetes.io/upstream-vhost - must match service externalName, removes hostname from request path (e.g. if this is missing and being tested through localhost, will likely encounter error: "No such bucket: localhost").
nginx.ingress.kubernetes.io/rewrite-target - passes matched asset URL path through to service.
The path.service.port.number in the Ingress definition must match whatever port the ExternalName service expects (443 in the case of our HTTPS traffic).
apiVersion: v1
kind: Service
metadata:
name: do-bucket-service
spec:
type: ExternalName
externalName: <zone>.digitaloceanspaces.com
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: do-bucket-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/rewrite-target: /<bucket>/$2
nginx.ingress.kubernetes.io/upstream-vhost: <zone>.digitaloceanspaces.com
spec:
rules:
- http:
paths:
- path: /path/to/static/assets(/|$)(.*)
pathType: Prefix
backend:
service:
name: do-bucket-service
port:
number: 443

sticky sessions kubernetes service with apache and ingress

I have an k8s Apache server which uses mod_jk to connect to different kubernetes services. mod_jk is sort of dummy here as workers are having k8s service URL. I am now trying to achieve sticky sessions based on JESSIONID in the cookie. I have traefik ingress controller which directs all requests to k8s Apache service. The requests is terminated at ingress level for TLS. What is the best way to achieve sticky session ?
I tried enabling sessionAffinity: ClientIP, but the client IP is always same. It is the ingress controller.
In the Kubernetes ingress object in the annotations label you have to define, which kind of Ingress will you use, so in your case: Traefik ingress controller. Please note, that the sticky session in Traefik is defined in the Service object with the annotation. Instead of a random cookie name, we define it as JSESSIONID.
Ingress object definition:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: traefik
labels:
app: session-affinity
name: session-affinity
spec:
tls:
- host: <address>
secretName:
rules:
- host: <address>
http:
paths:
- path: /
backend:
serviceName: session-affinity
servicePort: 8080
Service object definition:
apiVersion: v1
kind: Service
metadata:
name: session-affinity
labels:
app: session-affinity
annotations:
traefik.ingress.kubernetes.io/affinity: "true"
traefik.ingress.kubernetes.io/session-cookie-name: "JSESSIONID"
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
You can find more information in documentation.

Force HTTPS with Traefik

I am using traefik as ingress controller in a K8s cluster. I'd like to enforce all traffic via HTTPS.
It is a bit confusing the documentation because apparently there are different ways to do the same thing? Namely, I'd like to know what is the difference between these 2:
https://docs.traefik.io/user-guide/examples/#http-redirect-on-http
https://docs.traefik.io/configuration/backends/kubernetes/#general-annotations
If I use K8s is enough to use general annotations or I still have to edit the TOML file?
I have tried to use traefik.ingress.kubernetes.io/redirect-entry-point: https but doesn't find the service so I guess something is missing in my config.
If I remove the above line then everything works but HTTP -> HTTPS is, of course, not working. When I place the line back it returns a 404.
FWIW, the ingress definition is as follows (with traefik redirecting to 404):
- apiVersion: extensions/v1beta1
kind: Ingress
metadata:
generation: 1
name: rekover-ingress
namespace: prod
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/frontend-entry-points: http, https
traefik.ingress.kubernetes.io/redirect-entry-point: https
spec:
rules:
- host: www.xxx.com
http:
paths:
- backend:
serviceName: xxx-frontend
servicePort: 80
I have tried the very same configuration with nginx and changing to respective metadata and worked!. Below metadata used for nginx and Ingress:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
For completeness, I copy-paste the service definition for both nginx and traefik. First one works as expected:
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:xxxx
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
spec:
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: http
type: LoadBalancer
</code>
<code>
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service
namespace: ingress-prod
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:xxxx
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
- name: https
port: 443
targetPort: http
protocol: TCP
type: LoadBalancer
The first one is the toml Traefik configuration file, that can be modified in Kubernetes through a ConfigMap or in the Traefik container itself, or in the Traefik container command line (depending on how you deployed the Traefik Ingress Controller).
The second is what is mostly used to manage the configuration in the Traefik Ingress Controller through the Ingress Kubernetes resource.
You didn't post your Ingress definition but most likely it doesn't have a way to handle HTTPS and that's why when you add the annotation it sends traffic to port 443 and Traefik returns a 404.
To handle HTTPS/TLS you would need to enable it first (Create a K8s cert secret, configure TLS in the Ingress, etc). Or this is another example on how to enable it using a ConfigMap.
I give you the solution as valid because you provided a correct answer to the original question though the original question was badly formulated, my bad.
I found a related question which answers my question and worked like a charm:
Unable to redirect from http to https behind AWS load balancer
What frustates me is that, for instance, with nginx is just enough to use metadata annotations to force redirect to ssl whereas with traefik you have to edit the TOML file (or at least I didnt find the equivalent annotation for the problem).

Kubernetes Service pointing to External Resource

We have an existing website, lets say example.com, which is a CNAME for where.my.server.really.is.com.
We're now developing new services using Kubernetes. Our first service /login is ready to be deployed. Using a mock HTML server I've been able to deploy two pods with seperate services that map to example.com and example.com/login.
What I would like to do is get rid of my mock HTML server, and provide a service inside of the cluster, that points to our full website outside of the server. Then I can change the DNS for example.com to point to our kubernetes cluster and people will still get the main site from where.my.server.really.is.com.
We are using Traefik for ingress, and these are the changes I've made to the config for the website:
---
kind: Service
apiVersion: v1
metadata:
name: wordpress
spec:
type: ExternalName
externalName: where.my.server.really.is.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wordpress
annotations:
kubernetes.io/ingress.class: traefik
spec:
backend:
serviceName: wordpress
servicePort: 80
rules:
- host: example.com
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
Unfortunately, when I visit example.com, rather than getting where.my.server.really.is.com, I get a 503 with the body "Service Unavailable". example.com/login works as expected
What have I missed?
Following traefik documentation on using ExternalName
When specifying an ExternalName, Træfik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
This still requires setting up a proper port mapping on the Service from the Ingress port to the (external) Service port.
I believe you are missing the ports configuration of the Service. Something like
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
ports:
- name: http
port: 80
type: ExternalName
externalName: where.my.server.really.is.com
You can see a full example in the docs.