3

I am trying to create an API that serves HTTPS traffic publicly and is reachable by an IP address (not the domain), using a GKE cluster. Docker images have been tested locally. They were capable of serving HTTPS on their own, but as far as I've come to realize, this is not necessary for the setup that I am imagining.

So what I've come up with so far is to have a Kubernetes Service exposing it's 8443 port and having an Ingress load balancer mapping to that port and using self-signed certificates created using this tutorial - basic-ingress-secret referred in the template. The only thing I have skipped is the domain binding given I am not in the possession of a domain. I hoped it would bind the certificate to the external IP, but this is unfortunately not the case (have tried to attach an IP to a CN of the certificate, as some users have noted here).

This is my yaml for service:

apiVersion: v1
kind: Service
metadata:
  name: some-node
spec:
  selector:
    app: some
  ports:
  - protocol: "TCP"
    port: 8443
    targetPort: 8443
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: some-node-deploy
spec:
  selector:
    matchLabels:
      app: some
  replicas: 3
  template:
    metadata:
      labels:
        app: some
    spec:
      containers:
      - name: some-container
        image: "gcr.io/some-27417/some:latest"

This is my yaml for Ingress:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: basic-ingress
  annotations:
    kubernetes.io/ingress.allow-http: "false"
spec:
  tls:
  - secretName: basic-ingress-secret
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: some-node
          servicePort: 8443
Marc
  • 19,394
  • 6
  • 47
  • 51
  • It depends how your load balancer is configured. It can terminate TLS (speaking plain HTTP with your backend), operate at a lower level (eg: TCP, in which case you need certs that include the LB DNS), or terminate TLS and use a separate TLS connection to your backend. In all cases, you will either need a valid publicly-issued certificates, or a certificate that your app can verify (known self-signed CA, or certificate pinning for self-signed certificates). The very simples is probably terminating TLS at the load balancer and speaking HTTP with your backend. – Marc May 30 '20 at 18:56
  • As you can probably tell by the length of the previous comment, this is too broad for stackoverflow, – Marc May 30 '20 at 19:01
  • @Marc thank you for the suggestions and the comments, I have updated my post. Hopefully it is a bit more clearer now. – Roland Stojkoski May 30 '20 at 22:19

2 Answers2

1

It is way simpler than these documentations explain.

1.- Create the self-signed certs

openssl req -newkey rsa:2048 -nodes -keyout tls.key -out tls.csr
openssl x509 -in tls.csr -out tls.crt -req -signkey tls.key

2.- Create the secret

kubectl create secret tls basic-ingress-secret --cert tls.crt --key tls.key

3.- Create the Ingress object

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: basic-ingress
  annotations:
    kubernetes.io/ingress.allow-http: "false"
spec:
  tls:
  - secretName: basic-ingress-secret
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: some-node
          servicePort: 8443

Note: To make is work on GKE, your service must be of type NodePort

$ kubectl describe svc some-node
Name:                     some-node
Namespace:                default
Labels:                   run=nginx
Annotations:              <none>
Selector:                 run=nginx
Type:                     NodePort
IP:                       10.60.6.214
Port:                     <unset>  8443/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30250/TCP
Endpoints:                10.56.0.17:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
suren
  • 7,817
  • 1
  • 30
  • 51
0

I have found a final solution that suits my current needs.

The issue with the setup above was that I didn't had a nodePort: value setup and that the SSL certificate was not properly working so I have purchased a domain, secured a static IP for the Ingress load balancer using gcloud compute addresses create some-static-ip --globaland pointed that domain to the IP. I have then created a self-signed SSL certificate again following this tutorial and using my new domain.

The final yaml for the service:

apiVersion: v1
kind: Service
metadata:
  name: some-node
spec:
  selector:
    app: some
  ports:
  - port: 80
    targetPort: 30041
    nodePort: 30041
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: some-node-deploy
spec:
  selector:
    matchLabels:
      app: some
  replicas: 3
  template:
    metadata:
      labels:
        app: some
    spec:
      containers:
      - name: some-container
        image: "gcr.io/some-project/some:v1"

The final yaml for the LB:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: basic-ingress
  annotations:
    kubernetes.io/ingress.class: "gce"
    kubernetes.io/ingress.global-static-ip-name: "some-static-ip"
    kubernetes.io/ingress.allow-http: "false"
spec:
  tls:
  - secretName: basic-ingress-secret
  rules:
    - host: my.domain.com
      http:
        paths:
        - path: /some/*
          backend:
            serviceName: some-node
            servicePort: 80

The service now serves HTTPS traffic (only 443 port) on my.domain.com/some/* (placeholder domain and path). It is a simple HTTPS service setup that would require only a purchase of CA issued SSL certificate and a proper scaling configuration to be fully productionalized, from the DevOps standpoint. Unless someone has found some serious drawbacks to this setup.