<p>I have a simple web server exposed publicly on Kubernetes on GKE and a domain registered. I'm looking to add TLS to this so it's accessible via HTTPS. I've heard a lot about using Let's Encrypt and ended up attempting this: <a href="https://github.com/jetstack/cert-manager/blob/master/docs/tutorials/acme/quick-start/index.rst" rel="nofollow noreferrer">https://github.com/jetstack/cert-manager/blob/master/docs/tutorials/acme/quick-start/index.rst</a> but found it totally over-whelming. Is there a simpler approach to using Let's Encrypt given that my deployment is just a single service and pod?</p>

<p>The config I'm using is:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  labels:
    app: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: gcr.io/my-repo
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
        readinessProbe:
          initialDelaySeconds: 10
          httpGet:
            path: /healthz
            port: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: web-balancer-service
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    run: web
  type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-app

spec:
  rules:
  - host: my.domain.com
    http:
      paths:
      - path: /*
        backend:
          serviceName: web-balancer-service
          servicePort: 8080
</code></pre>

<p>========================================</p>

<p>EDIT: Following @Utku Özdemir's suggestion I tried to codify those changes into YAML. I created the IP address with </p>

<pre><code>gcloud compute addresses create example-ip-address --global
</code></pre>

<p>And the certificate and provisioning with: <a href="https://gist.github.com/nickponline/ab74d3d179e21474551b7596c6478eea" rel="nofollow noreferrer">https://gist.github.com/nickponline/ab74d3d179e21474551b7596c6478eea</a> </p>

<p>Everything provisions correctly but when I inspect the ManagedCertificates with <code>kubectl describe ManagedCertificates example-certificate</code> is says </p>

<pre><code>Spec:
  Domains:
    app.domain.xyz
Status:
  Certificate Name:    xxxxxxxxxxxxxxxxxx
  Certificate Status:  Provisioning
  Domain Status:
    Domain:  app.domain
    Status:  FailedNotVisible
Events:      &lt;none&gt;
</code></pre>

<p>I've waited 24 hours so assume that this isn't going to change. </p>

nickponline
<p>Since you use the ingress controller of the GKE itself, when you create an <em>Ingress</em> resource, it triggers the creation of a <em>Load Balancer</em> resource in the Google Cloud Platform. Normally, SSL termination is a responsibility of the ingress controller, therefore that GCP load balancer is responsible of doing the SSL termination.</p>

<p>This means, cert-manager will not work for your case, since the certificates will live outside of your cluster, and the traffic <strong>will be already SSL terminated</strong> before coming in your cluster.</p>

<p>Luckily, GCP has self-provisioned SSL (Let's Encrypt) support. To make use of that, yo need to follow the steps below:</p>

<ol>
<li><p>Go to the Load Balancing screen on GCP, switch to advanced view, and jump to the Certificates tab (or simply click <a href="https://console.cloud.google.com/net-services/loadbalancing/advanced/sslCertificates/list" rel="nofollow noreferrer">here</a>).</p></li>
<li><p>Create a new SSL certificate, with "Create Google-managed certificate" chosen. To the domain field, write down the exact domain you want the SSL certificate for. It should look like this:</p></li>
</ol>

<p><a href="https://i.stack.imgur.com/lwT5Im.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lwT5Im.png" alt="enter image description here"></a></p>

<ol start="3">
<li>Go to the <a href="https://console.cloud.google.com/networking/addresses/list" rel="nofollow noreferrer">External IP Addresses</a> screen, and reserve a new static IP address. Choose the type to be global (at the time of writing, GCP ingress controller only supports global IP addresses). Should look like this:</li>
</ol>

<p><a href="https://i.stack.imgur.com/i7djbm.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/i7djbm.png" alt="enter image description here"></a></p>

<ol start="4">
<li>Take the static IP that you reserved (in this example it is <code>34.95.84.106</code>)</li>
</ol>

<p><a href="https://i.stack.imgur.com/C9CPE.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/C9CPE.png" alt="enter image description here"></a></p>

<p>Go to your domain registrar, and add an <code>A</code> type record for your domain (the one in the SSL certificate) to point to the static IP you allocated. In this example, it would be <code>my-app.example.com -&gt; 34.95.84.106</code>.</p>

<ol start="5">
<li>Finally, you will need to edit your ingress to put 2 annotations, so it will hint the Google Cloud's Ingress Controller to use the static IP you reserved, and the certificate you created. See the ingress example below:</li>
</ol>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-app
  annotations:
    ingress.gcp.kubernetes.io/pre-shared-cert: my-ssl-certificate # the name of the SSL certificate resource you created
    kubernetes.io/ingress.global-static-ip-name: my-static-ip # the name of the static ip resource you created
    kubernetes.io/ingress.allow-http: "false" # if you want to block plain http
spec:
  rules:
    - host: my-app.example.com
      http:
        paths:
          - path: /*
            backend:
              serviceName: web-balancer-service
              servicePort: 8080
</code></pre>

<p>Apply it, and verify that the changes are reflected by going to the Load Balancers screen on GCP.</p>

<h3>Important Notes:</h3>

<ul>
<li><p>If there already is a GCP Load Balancer that is created by an Ingress, the <strong>changes you do (annotations) on the ingress will not reflect to the existing load balancer</strong>. Therefore, delete your existing ingress, make sure the existing load-balancer disappears, and create the ingress with correct annotations, so the load balancer will be configured correctly.</p></li>
<li><p>For the Let's Encrypt provisioning to work, your DNS record should be in place. It checks the owner of the domain using DNS before issuing the certificate. Also, the initial <strong>provisioning can take quite some time</strong> (up to half an hour).</p></li>
</ul>
