Search
Guoping Jia

Generating self-signed certificates using cert-manager for Kubernetes in HPE GreenLake for Private Cloud Enterprise

March 11, 2024

This blog post describes the details steps on how to generate a self-signed certificate using cert-manager for Kubernetes (K8s) in HPE GreenLake for Private Cloud Enterprise. The generated self-signed certificates can be used by DevOps teams and developers to configure Transport Layer Security (TLS) termination and expose applications deployed in the K8s cluster securely via HTTPS.

Overview

HPE GreenLake for Private Cloud Enterprise: Containers, one of the HPE GreenLake cloud services available on the HPE GreenLake for Private Cloud Enterprise, allows customers to create a K8s cluster, view details about existing clusters, and deploy containerized applications to the cluster. It provides an enterprise-grade container management service using open source K8s.

Once applications are deployed in a cluster, a common requirement is to expose the applications so that they can be securely accessed over HTTPS. This requires getting a valid SSL/TLS certificate in K8s. Generating and managing SSL/TLS certificates in K8s is not always easy. There is a list of popular tools and utilities, e.g, . OpenSSL, CloudFlare’s CFSSL, OpenVPN’s Easy-RSA, etc, that you can use for generating certificates.

However, you still need to follow up that with creating the root certificate authorities, generating certificate signing requests (CSRs), and signing the certificates. The process to generate those items is not very intuitive. Most often than not, it requires the help of a DevOps engineer as well as assistance from different teams who are involved in installing and configuring the certificate chain.

This blog post describes the detailed steps involved in the process of generating a self-signed certificate using cert-manager for K8s in HPE GreenLake for Private Cloud Enterprise. Cert-manager integrates seamlessly with K8s for automated handling of certificates. It aligns well with the K8s resource model. This makes cert-manager a native and powerful solution for creating and managing certificates within K8s clusters.

Prerequisites

Before starting, make sure you have the following:

  • A K8s cluster, being provisioned in HPE GreenLake for Private Cloud Enterprise
  • The kubectl CLI tool, together with the kubeconfig file for accessing the K8s cluster
  • The optional openssl CLI tool, for validating the generated certificate

Cert-manager

Cert-manager, a popular open source certificate management add-on designed to work with K8s, streamlines the process of acquiring, renewing, and utilizing SSL/TLS certificates within a K8s cluster. When deployed in a K8s cluster, cert-manager introduces two custom resource definitions (CRDs): Issuer and Certificate. These CRDs automate the generation and renewal of certificates for various scenarios in K8s. Cert-manager can obtain certificates from a variety of certificate authorities (CAs), including Let’s Encrypt, HashiCorp Vault, and private PKIs. It can also be configured to generate self-signed certificates if needed. When cert-manager creates a certificate, it makes it available to the entire cluster by storing the certificate as a K8s Secret object, which can be mounted by application Pods or used by an Ingress controller. This makes the certificate accessible across all namespaces within the K8s cluster.

Generate a self-signed certificate

Install cert-manager

As shown on the cert-manager installation page, cert-manager can be installed by typing the following kubectl apply command:

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.yaml
namespace/cert-manager created
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
serviceaccount/cert-manager-cainjector created
serviceaccount/cert-manager created
serviceaccount/cert-manager-webhook created
configmap/cert-manager created
configmap/cert-manager-webhook created
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrole.rbac.authorization.k8s.io/cert-manager-cluster-view created
clusterrole.rbac.authorization.k8s.io/cert-manager-view created
clusterrole.rbac.authorization.k8s.io/cert-manager-edit created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
role.rbac.authorization.k8s.io/cert-manager:leaderelection created
role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
service/cert-manager created
service/cert-manager-webhook created
deployment.apps/cert-manager-cainjector created
deployment.apps/cert-manager created
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created

The latest cert-manager v1.14.3 will be installed to the namespace cert-manager. Type the following command to check that all the Pods are showing a Running status:

$ kubectl get all -n cert-manager
NAME                                           READY   STATUS    RESTARTS   AGE
pod/cert-manager-6bcdd5f7c-f7lfw               1/1     Running   0          3m36s
pod/cert-manager-cainjector-5d4577b4d9-jmpsp   1/1     Running   0          3m36s
pod/cert-manager-webhook-bf957dc77-s9r2g       1/1     Running   0          3m36s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/cert-manager           ClusterIP   10.109.28.203   <none>        9402/TCP   3m39s
service/cert-manager-webhook   ClusterIP   10.100.82.119   <none>        443/TCP    3m38s

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cert-manager              1/1     1            1           3m37s
deployment.apps/cert-manager-cainjector   1/1     1            1           3m38s
deployment.apps/cert-manager-webhook      1/1     1            1           3m37s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/cert-manager-6bcdd5f7c               1         1         1       3m38s
replicaset.apps/cert-manager-cainjector-5d4577b4d9   1         1         1       3m39s
replicaset.apps/cert-manager-webhook-bf957dc77       1         1         1       3m38s

As part of cert-manager installation, a list of cert-manager related CRDs has been added to the cluster:

$ kubectl get crds | grep cert-manager
certificaterequests.cert-manager.io                                 2024-02-02T15:42:53Z
certificates.cert-manager.io                                        2024-02-02T15:42:53Z
challenges.acme.cert-manager.io                                     2024-02-02T15:42:54Z
clusterissuers.cert-manager.io                                      2024-02-02T15:42:55Z
issuers.cert-manager.io                                             2024-02-02T15:42:55Z
orders.acme.cert-manager.io                                         2024-02-02T15:42:56Z

Create an Issuer

An Issuer in cert-manager is a K8s CRD resource that represents a certificate authority (CA) that's able to generate a signed certificate by honoring certificate signing request (CSR). All cert-manager certificates require a referenced issuer that is in a ready condition to attempt to honor the request.

Here is a self-signed issuer YAML manifest file issuer-selfsigned.yaml:

$ cat issuer-selfsigned.yaml                                                            
apiVersion: cert-manager.io/v1                                                                                                                   
kind: Issuer                                                                                                                                     
metadata:                                                                                                                                         
 name: cfe-selfsigned-issuer                                                                                                                     
spec:                                                                                                                                             
 selfSigned: {}

Type the following commands to create a namespace in which you want to generate certificates and deploy the CRD Issuer resource to this namespace. Replace the sample namespace cfe-apps in the commands with your own namespace.

$ kubectl create ns cfe-apps
namespace/cfe-apps created

$ kubectl apply -f issuer-selfsigned.yaml -n cfe-apps
issuer.cert-manager.io/cfe-selfsigned-issuer created

Type the following command to check the deployed issuer in the namespace. The issuer should show READY as True.

$ kubectl get issuer -n cfe-apps
NAME                    READY   AGE

cfe-selfsigned-issuer   True    7s

If you want to be able to request certificates from any namespace in a cluster, use the CRD resource called ClusterIssuer.

Here is a sample ClusterIssuer YAM manifest file clusterissuer.yaml:

$ cat clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-cluster-issuer
spec:
  selfSigned: {}

Generate a certificate

You can use the CRD resource Certificate to generate a self-signed certificate.

Here is a sample Certificate YAML manifest file certificate.yaml :

$ cat certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
 name: cfe-selfsigned-tls
spec:
 secretName: cfe-tls-key-pair
 isCA: true
 issuerRef:
   name: cfe-selfsigned-issuer
   kind: Issuer
 commonName: "example.com"
 dnsNames:
 - nginx.example.com
 - example.com

In this YAML file, the commonName is set to a sample domain 'example.com'. The dnsNames includes 'example.com' and its subdomain 'nginx.example.com'.

Cert-manager supports the generation of wildcard certificates, e.g., using '*.example.com', which allows one to secure multiple subdomains under a single certificate. Wildcard certificates cover all subdomains under the specified domain. You need to be cautious when using them, as they grant access to any subdomain matching the pattern.

Type the following command to generate the certificate in the namespace cfe-apps:

$ kubectl apply -f certificate.yaml -n cfe-apps
certificate.cert-manager.io/cfe-selfsigned-tls created

Check the generated certificate in the namespace cfe-apps by typing the following command:

$ kubectl get certificate -n cfe-apps
NAME                 READY   SECRET             AGE
cfe-selfsigned-tls   True    cfe-tls-key-pair   23s

The K8s secret cfe-tls-key-pair will be created automatically in the same namespace as part of certificate deployment. Type the command shown below to check it:

$ kubectl get secrets -n cfe-apps cfe-tls-key-pair
NAME               TYPE                DATA   AGE
cfe-tls-key-pair   kubernetes.io/tls   3      52s

The secret cfe-tls-key-pair contains 3 keys, ca.crt, tls.crt and tls.key, which can be checked using the option -o yaml in the above get secrets command.

Test the certificate

Type the following openssl command to check the generated certificate:

$ openssl x509 -in <(kubectl get secret -n cfe-apps cfe-tls-key-pair -o jsonpath='{.data.tls\.crt}' | base64 -d)
-text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2a:2a:5d:0f:d1:e2:6f:60:3e:8a:93:4f:f4:e8:52:1e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = example.com
        Validity
            Not Before: Feb 21 14:17:18 2024 GMT
            Not After : May 21 14:17:18 2024 GMT
        Subject: CN = example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b7:7d:95:7f:55:a7:32:fd:66:b2:78:c0:2b:1f:
                    1f:69:c6:de:1f:85:eb:fb:2b:69:f3:60:23:df:9d:
                    3e:3d:41:df:c9:6b:b0:92:80:fe:6a:6f:19:4d:61:
                    20:3e:fc:19:af:f1:1d:5e:f6:b6:4f:17:5d:76:99:
                    3f:f4:d3:4a:70:15:f8:d5:3e:02:5c:c4:29:32:75:
                    cd:e3:5a:07:7d:ea:47:71:37:3b:3d:36:89:36:e5:
                    8f:0e:03:57:ab:99:b3:6d:47:67:8a:6b:3b:2b:61:
                    b0:08:96:a6:a2:5d:46:ed:ee:f3:5a:e3:6b:1d:05:
                    08:f1:ab:1b:ea:49:a3:2f:0d:82:37:80:76:00:18:
                    77:99:39:08:2e:06:54:28:24:e2:c8:9f:48:9c:ec:
                    75:0e:5e:a6:7b:ce:0b:68:96:d1:1a:4e:56:e1:ca:
                    42:ab:8e:11:a8:37:e1:70:ae:25:e3:2f:26:f1:7c:
                    95:fa:da:48:57:1f:a3:d7:47:84:86:9d:76:b3:99:
                    a5:ef:10:98:96:31:ee:32:31:05:bc:5a:c0:94:bd:
                    25:ba:d6:86:32:d1:a6:3e:8c:21:99:a8:96:d6:5d:
                    69:35:01:8e:4f:d8:e9:90:78:17:ce:ac:4a:f8:13:
                    59:9b:e3:a8:9b:59:cc:c6:5f:5b:ca:6c:73:5e:e6:
                    88:f9
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                53:55:6D:56:AA:75:E2:87:9E:BB:C2:C7:45:32:2F:E3:1C:FF:17:62
            X509v3 Subject Alternative Name:
                DNS:nginx.example.com, DNS:example.com
    Signature Algorithm: sha256WithRSAEncryption
         69:e4:ae:bb:15:c1:d7:1a:54:49:10:6b:04:f9:1b:ed:bf:64:
         0f:da:5e:b8:c2:e7:e2:d9:45:9e:66:92:0f:ce:f5:c9:5f:aa:
         b3:28:36:cd:16:da:6a:60:7f:eb:1d:85:fe:3a:38:65:71:0f:
         eb:da:e8:9e:1b:dc:f5:b7:14:4f:70:00:fd:bf:44:ed:37:35:
         bc:67:c7:4f:68:bc:5e:3b:bd:64:aa:5c:cd:1a:4f:11:90:c4:
         6f:6a:d2:4b:90:4c:25:e7:ab:83:12:d7:38:b1:bf:70:8c:d5:
         cc:cb:70:70:b6:de:dc:8f:66:21:42:88:d5:7e:59:5f:6e:83:
         73:81:e4:63:57:d1:c6:63:c0:9a:49:09:44:b5:d0:33:6b:3b:
         fd:3e:e4:c7:b7:d4:e4:72:0d:36:cf:a8:31:26:e3:ce:55:9f:
         46:b8:fd:ab:7c:cc:2a:4b:e2:a6:a5:cd:2f:0c:3a:b1:2d:84:
         1a:51:8b:e8:73:0f:cb:49:2e:a2:a6:ed:d5:e2:e8:cf:79:44:
         b9:2b:00:03:86:1a:a6:33:d4:20:33:9c:04:71:43:2d:9c:66:
         3b:13:9b:6f:9f:f6:5f:f2:e0:e4:4a:04:64:c3:e6:bd:78:18:
         19:22:d9:98:b5:47:85:0d:bd:b6:56:44:e6:89:34:30:90:20:
         36:63:4f:1e

The line X509v3 Subject Alternative Name contains the dnsNames specified in the YAML file certificate.yaml during the certificate generation.

Integrate certificate with applications

There are several ways to integrate the generated certificates into applications deployed in the K8s cluster and configure applications to be accessed securely over HTTPS.

The simplest way is to create the K8s Deployment resource with TLS block and containerPort configuration.

Here is one sample Nginx Deployment YAML manifest file nginx-deployment.yaml that integrates the generated certificate:

$ cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  replicas: 1
  template:
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 443
      tls:
      - secretName: cfe-tls-key-pair

By specifying the containerPort as 443 and referring the secretName to the generated K8s secret cfe-tls-key-pair under tls section, it enables TLS termination for the Nginx application.

There is another way to integrate the certificate and configure it using the K8s Ingress resource with TLS parameters. This configuration requires a working Ingress controller setup in the cluster. There is a list of Ingress controllers, like: Traefik, HAProxy, Nginx Ingress controller, you can deploy in the cluster.

Here is one such sample Ingress YAML manifest file ingress-nginx-selfsigned.yaml:

$ cat ingress-nginx-selfsigned.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress-selfsigned
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/issuer: "cfe-selfsinged-issuer"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - nginx.example.com
    secretName: cfe-tls-key-pair
  rules:
  - host: nginx.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-app
            port:
              number: 80

It assumes the Nginx Ingress controller is deployed in the cluster. It configures the TLS block with the hostname 'nginx.example.com' and the generated K8s secret.

One benefit of this approach is that the sample Nginx application can be deployed in the cluster with the default service type ClusterIP, which provides internal connectivity and can solely be accessed from within the cluster. The Ingress controller will provide external access and handle SSL by accessing the certificate in the cluster and route the traffic to the deployed Nginx application in the backend.

Type the following command to deploy the Ingress resource to the namespace cfe-apps:

$ kubectl apply -f ingress-nginx-selfsigned.yaml -n cfe-apps
ingress.networking.k8s.io/nginx-ingress-selfsigned created

After deploying the Ingress using the above command, together with Nginx application deployment, to the namespace cfe-apps, you can validate the Ingress TLS using the browser.

Start the browser and type the URL nginx.example.com, it will be rediected over HTTPS with the warning message 'Your connection is not private':

You can click Not secure and start the Certificate Viewer to check the TLS certificate before clicking Proceed to nginx.example.com (unsafe) to go to the Nginx page:

Conclusion

This blog post described the steps to generate a self-signed certificate using cert-manager for K8s in HPE GreenLake for Private Cloud Enterprise. Self-signed certificates provide an easy way to prove your own identity for the applications deployed in K8s cluster. This is a good option for development and testing environments. However, because self-signed certificates are not trusted certificates, they should not be used for production applications. For production use cases, you can try out cert-manager with Lets Encrypt. You can refer to cert-manager documentation on how to use it with the type of Let’s Encrypt challenges, as well as other sources than Let’s Encrypt.

Please keep coming back to the HPE Developer Community blog to learn more about HPE GreenLake for Private Cloud Enterprise.

Related

Kiran Kumar Mavatoor

Accessing HPE Ezmeral Data Fabric Object Storage from Spring Boot S3 Micro Service deployed in K3s cluster

Sep 13, 2021
Denis Choukroun

Deep Learning Model Training – A First-Time User’s Experience with Determined - Part 1

Apr 14, 2022
Denis Choukroun

Deep Learning Model Training – A First-Time User’s Experience with Determined – Part 2

May 3, 2022
Guoping Jia

Exposing applications using Ingress and TLS termination on Kubernetes in HPE GreenLake for Private Cloud Enterprise

Mar 20, 2024
Guoping Jia

Getting started with volume snapshots on a Kubernetes cluster in HPE GreenLake for Private Cloud Enterprise

Jan 23, 2024
Guoping Jia

How to backup and restore stateful applications on Kubernetes using Kasten K10 in HPE GreenLake for Private Cloud Enterprise

Jan 26, 2024
Suzanne Ferry

Kubernetes Application Containers: Managing Containers and Cluster Resources

Jul 10, 2020
Guoping Jia

Adding a monitoring stack to a Kubernetes cluster using Prometheus and Grafana in HPE GreenLake for Private Cloud Enterprise

Jan 25, 2024

HPE Developer Newsletter

Stay in the loop.

Sign up for the HPE Developer Newsletter or visit the Newsletter Archive to see past content.

By clicking on “Subscribe Now”, I agree to HPE sending me personalized email communication about HPE and select HPE-Partner products, services, offers and events. I understand that my email address will be used in accordance with HPE Privacy Statement. You may unsubscribe from receiving HPE and HPE-Partner news and offers at any time by clicking on the Unsubscribe button at the bottom of the newsletter.

For more information on how HPE manages, uses, and protects your personal data please refer to HPE Privacy Statement.