Difficulties creating a SSL web service on GKE

Viewed 200

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
2 Answers

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>

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.

Related