TheKoguryo's Tech Blog

Version 2023.06.19

Warning

This content has been generated by machine translation. The translations are automated and have not undergone human review or validation.

4.1.4 TLS termination on NGINX Ingress Controller (feats. Let’s Encrypt)

Check the settings for SSL external ingress in the Ingress Controller.

Using Self-Signed Certificates

Learn how to create and use Self-Signed certificates for testing purposes. In a real environment, a certificate issued by an authorized certification authority is used. Only the self-signed certificate issuance process is replaced, and the TLS Secret registration process is the same.

References

Create a certificate

  1. Create a certificate with the following command in Cloud Shell or your environment. It is not necessary to use a certificate issued by an authorized certification authority.

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
    
  2. Create a TLS Secret.

    kubectl create secret tls tls-secret --key tls.key --cert tls.crt
    
  3. Execution result

    oke_admin@cloudshell:~ (ap-seoul-1)$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
    Generating a 2048 bit RSA private key
    *************************************************************************************************************************************************************+++++
    ****************************************************************************************************************************+++++
    writing new private key to 'tls.key'
    -----
    oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
    secret/tls-secret created
    

Deploy TLS Ingress resources

  1. Deploy the sample app for testing. Use the same app you used for PATH-based routing.

    kubectl create deployment nginx-blue --image=thekoguryo/nginx-hello:blue
    kubectl expose deployment nginx-blue --name nginx-blue-svc --port 80
    kubectl create deployment nginx-green --image=thekoguryo/nginx-hello:green
    kubectl expose deployment nginx-green --name nginx-green-svc --port 80
    
  2. Write the ingress setup YAML (tls-termination.yaml).

    • Use the self-signed certificate name you created earlier as spec.tls.secretName.
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-tls-termination
      annotations:
        kubernetes.io/ingress.class: nginx
    spec:
      tls:
      - secretName: tls-secret
      rules:
      - host: blue.ingress.thekoguryo.ml
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-blue-svc
                port:
                  number: 80
      - host: green.ingress.thekoguryo.ml
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-green-svc
                port:
                  number: 80
    
  3. Delete the existing test ingress and deploy the created tls-termination.yaml.

    oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl apply -f tls-termination.yaml 
    ingress.networking.k8s.io/ingress-tls-termination created
    oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get ingress
    NAME                      CLASS    HOSTS                                                    ADDRESS   PORTS     AGE
    ingress-tls-termination   <none>   blue.ingress.thekoguryo.ml,green.ingress.thekoguryo.ml             80, 443   5s
    

Validate TLS application result

  1. Connect to each host name applied in the ingress rule and check the result.

    As shown below, you will be connected via https and a warning message will appear due to the Self-Signed certificate.

    image-20211207124621301

  2. Click Advanced and select Go to that page.

    image-20211207124712582

  3. Check the certificate information through the browser address bar menu. With Self-Signed Certificates, you can see warnings that the root certificate is not trusted.

    image-20211207125115259

    image-20211207125154597

Using Let’s Encrypt & Cert Manager

Let’s Encrypt is a free certificate issuing site where you can get a certificate to use for TLS. Instead, it is only valid for 90 days and must be renewed before expiration. Kubernetes can automatically renew through Cert Manager.

Installation notes

Deploy Cert Manager

  1. Deploy Cert Manager in Cloud Shell or in your environment.

    kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.yaml
    
  2. Check the installation

    Check that the resources in the cert-manager namespace are running normally.

    oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get all -n cert-manager
    NAME                                          READY   STATUS    RESTARTS   AGE
    pod/cert-manager-55658cdf68-sk5nj             1/1     Running   0          18s
    pod/cert-manager-cainjector-967788869-b77w2   1/1     Running   0          18s
    pod/cert-manager-webhook-7b86bc6578-pnxtg     1/1     Running   0          18s
    
    NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/cert-manager           ClusterIP   10.96.100.11   <none>        9402/TCP   19s
    service/cert-manager-webhook   ClusterIP   10.96.212.15   <none>        443/TCP    19s
    
    NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/cert-manager              1/1     1            1           19s
    deployment.apps/cert-manager-cainjector   1/1     1            1           19s
    deployment.apps/cert-manager-webhook      1/1     1            1           19s
    
    NAME                                                DESIRED   CURRENT   READY   AGE
    replicaset.apps/cert-manager-55658cdf68             1         1         1       19s
    replicaset.apps/cert-manager-cainjector-967788869   1         1         1       19s
    replicaset.apps/cert-manager-webhook-7b86bc6578     1         1         1       18s
    

Configure Let’s Encrypt Issuer

In this example, Staging Issuer and Production Issuer provided by Let’s Encrypt can be used. Here we will use the Staging Issuer for testing purposes.

  1. Let’s Encrypt Staging Issuer Setup

    In the https://cert-manager.io/docs/tutorials/acme/example/staging-issuer.yaml file, only the email part is modified and reflected.

    Use the ClusterIssuer type for use with the entire Kubernetes cluster, rather than an Issuer used only for namespaces.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-staging
    spec:
      acme:
        # The ACME server URL
        server: https://acme-staging-v02.api.letsencrypt.org/directory
        # Email address used for ACME registration
        email: user@example.com
        # Name of a secret used to store the ACME account private key
        privateKeySecretRef:
          name: letsencrypt-staging
        # Enable the HTTP-01 challenge provider
        solvers:
        - http01:
            ingress:
              class: nginx
    
  2. Let’s Encrypt Production Issuer

    The Production Issuer can be installed in the same way using the https://cert-manager.io/docs/tutorials/acme/example/production-issuer.yaml file. However, if you repeat deletion and creation due to usage limit, you may be hit by the rate limit.

  3. Apply settings

    oke_admin@cloudshell:$ (ap-seoul-1)$ kubectl create --edit -f https://cert-manager.io/docs/tutorials/acme/example/staging-issuer.yaml
    issuer.cert-manager.io/letsencrypt-staging created
    

Deploy TLS Ingress resources

  1. Use the test app as it was before.

  2. Write the ingress setup YAML (tls-termination-cert-manager.yaml).

    • As of the document creation date (STAGING) Due to the expiration of the Doctored Durian Root CA, the certificate may appear as invalid even when using a staging issuer. The cert manager issuer will use the production issuer. Instead, the production issuer may hit the limit if it repeats the creation.
    • cert-manager.io/cluster-issuer: letsencrypt-staging config we just created, use cluster-issuer not issuer.
    • Specify the storage name to store tls under spec.tls and the domain name to be issued and used
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-tls-termination-cert-manager
      annotations:
        kubernetes.io/ingress.class: nginx
        cert-manager.io/cluster-issuer: "letsencrypt-staging"
    spec:
      tls:
      - secretName: ingress-thekoguryo-ml-tls
        hosts:
        - green.ingress.thekoguryo.ml
        - blue.ingress.thekoguryo.ml
      rules:
      - host: green.ingress.thekoguryo.ml
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-green-svc
                port:
                  number: 80
      - host: blue.ingress.thekoguryo.ml
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-blue-svc
                port:
                  number: 80
    
  3. Delete the existing test ingress and distribute the created tls-termination-cert-manager.yaml.

    oke_admin@cloudshell:ingress-nginx (ap-seoul-1)$ kubectl apply -f tls-termination-cert-manager.yaml 
    ingress.networking.k8s.io/ingress-tls-termination-cert-manager created
    oke_admin@cloudshell:ingress-nginx (ap-seoul-1)$ kubectl get ingress
    NAME                                   CLASS    HOSTS                                                    ADDRESS   PORTS     AGE
    ingress-tls-termination-cert-manager   <none>   blue.ingress.thekoguryo.ml,green.ingress.thekoguryo.ml             80, 443   9s
    
  4. Confirm issuance of the certificate

    A secret is created with the specified spec.tls.secretName, and when the certificate status (READY) becomes True, it was issued normally.

    oke_admin@cloudshell:ingress-nginx (ap-seoul-1)$ kubectl get secret
    NAME                        TYPE                                  DATA   AGE
    default-token-jbv7p         kubernetes.io/service-account-token   3      3d19h
    ingress-thekoguryo-ml-tls   kubernetes.io/tls                     2      15m
    letsencrypt-staging         Opaque                                1      16m
    oke_admin@cloudshell:ingress-nginx (ap-seoul-1)$ kubectl get certificate
    NAME                        READY   SECRET                      AGE
    ingress-thekoguryo-ml-tls   True    ingress-thekoguryo-ml-tls   16m
    

Validate TLS application result

  1. Connect to each host name applied in the ingress rule and check the result.

    As shown below, it is accessed via https and is displayed as a valid certificate without warning unlike Self-Signed certificates.

    image-20211207185839881

    image-20211207185954775

  2. All the requested hosts are registered in the DNS alternative address, and the blue app is also connected without an authentication error.

    image-20211207190233212

Resolve authentication error due to Let’s Encrypt Root CA change

  1. When using Staging Issuer, an authentication error may occur when accessing a web browser due to the expiration of (STAGING) Doctored Durian Root CA X3. Production Issuers don’t have that issue.

    image-20211207190731003

  2. If this error occurs, download the changed new Root CA from the let’s encrypt site and register it in the browser.

  3. Download the file

    https://letsencrypt.org/certs/staging/letsencrypt-stg-root-x1.pem

  4. Add the downloaded Root CA to your browser (based on Chrome browser)

    • Go to Chrome Browser > Settings > Privacy & Security > Certificate Management

    • Click Import Certificate

      image-20211207190758097

    • Select the downloaded file

      image-20211207190827049

    • Install certificate

      image-20211207190845774

    • Check after certificate registration

      I see the certificate I just enrolled (STAGING) with Trusted Root Certification Authorities

      image-20211207190923997

    • If you access the web page of the app again after the certificate is registered, no authentication error occurs and the authentication path is displayed as shown below.

      image-20211207185954775



As an individual, this article was written with my personal time. There may be errors in the content of the article, and the opinions in the article are personal opinions.

Last updated on 7 Dec 2021