Kubernetes - Create a certificate from namecheap

Michael Roma on Nov 25, 2022

In this article, I will describe how to purchase a certificate from namecheap.com and add to your Kubernetes instance. I will also show how to reference the in an Ingress object to act as the certificate for your website.

First, you will want to find a place to get your SSL certificate. The site I’m going to use for my example is https://www.namecheap.com/.

Next, you will generate a CSR (Certificate Signing Request). In the example below, I’m using the openssl tool to generate one. You will use the -keyout and -out flags to get the key and CSR that we will use later.

openssl req -new -newkey rsa:4096-nodes -keyout mywebsite_com.key -out mywebsite_com.csr

You will be prompted to enter a passphase, it requires it to be at least 4 characters. You will also need to enter in location details and your organization information. For this example, I did not set a challenge password.

# openssl req -new -newkey rsa:4096-nodes -keyout mywebsite_com.key -out mywebsite_com.csr
Generating a RSA private key
................................................++++
..........................................................++++
writing new private key to 'mywebsite_com.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MA
Locality Name (eg, city) []:Boston
Organization Name (eg, company) [Internet Widgits Pty Ltd]:RomaCode
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:www.mywebsite.com
Email Address []:webmaster@romacode.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

If you check your current directory, you should see two new files for the key and CSR:

# ls -l
total 8.0K
-rw-r--r-- 1 mroma mroma 1.7K Nov 27 11:47 mywebsite_com.csr
-rw------- 1 mroma mroma 3.4K Nov 27 11:46 mywebsite_com.key

Now head back over to the SSL certificate site and purchase a certificate. In this case, I used namecheap.com and purchased the PositiveSSL option.

When prompted, paste in the contents of the CSR file that we generated above. This will get the process started.

Next you will need to validate the domain. In this case, I used the DNS validation option and created the TXT record they requested. This validation can take up to 30 minutes to process.

Once the domain is validated, you will then be able to download your certificate. Specifically, we will be looking for the .crt file.

Next, we are going to create a new Kubernetes object for the certificate. We will be creating an object of type Secret. Make sure to have your .key file available for this. Below is the command to run to create a new Kubernetes Secret in the current namespace.

kubectl create secret tls tls-mywebsite-com --key mywebsite_com.key --cert www_mywebsite_com.crt

If we query the secrets now, we should see the new one created:

# kubectl get secret
NAME                  TYPE                DATA   AGE
tls-mywebsite-com     kubernetes.io/tls   2      28d

Last, we will use this secret in an Ingress object so it can act as the certificate for your website. Below is an example Ingress and Service objects that can be used. The tls section of the Ingress object is the main detail here.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress  
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  tls:
    - hosts:
        - www.website.com
      secretName: tls-website-com
  rules:
  - host: www.website.com
    http:
      paths:
        - path: /
          backend:
            serviceName: SERVICE_NAME
            servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: SERVICE_NAME
spec:
  type: ClusterIP
  ports:
  - port: 80
    name: http
    protocol: TCP
    targetPort: 8081
  selector:
    app: APP_NAME