Roman KlimenkoBlogPhotography

Create a self-signed TLS-certificate

January 30, 2023


You may need a self-signed certificate whenever you do a local development or host a web application in your local network.

In this article, I create a wildcard certificate for *.home.local to use on my local Kubernetes cluster.

First, we need OpenSSL – cryptography and SSL/TLS Toolkit. In this article, I assume you already have it installed on your computer.

Now, to create a certificate, we need to perform these simple steps:

1. Generate a CA (certificate authority) private key

genrsa generates a Triple DES-encrypted and password-protected 2048-bits long private key to a file named ca.key:

openssl genrsa -des3 -out ca.key 2048

Expected output:

  • a file called ca.key with the first line -----BEGIN RSA PRIVATE KEY-----.
2. Generate a root certificate

Now, let's create a

openssl req -x509 -new -nodes -key ca.key -days 1825 -out ca.pem


  • openssl reqa command to generate PKCS#10 certificate requests and certificates:
  • -x509 – this option outputs a certificate instead of a certificate request.
  • -new – this option generates a new certificate request. It will prompt the user for the relevant field values.
  • -nodes – i.e., "no DES": if this option is specified, then if a private key is created, it will not be encrypted.
  • -key ca.key – this option provides the private key for signing a new certificate or certificate request.
  • -days 1825 – when -x509 is in use, this specifies the number of days to certify the certificate for.
  • -out ca.pem – specifies the output filename to write to or standard output by default.

Expected output:

  • after you enter the CA pass phrase (remember if from the previous step?),
  • and after you answer several questions,
  • you get a file named ca.pem with the first line -----BEGIN CERTIFICATE-----.
3. Create a CA-signed certificate

Now, when we have a root certificate, we can create a new certificate signed by our root certificate:

openssl genrsa -out home.local.key 2048

Here, we use our friend genrsa that we already used in the first step.

Expected output:

  • a file named home.local.key with the first line -----BEGIN RSA PRIVATE KEY-----.
4. Create a CSR (certificate signing request)
openssl req -new -key home.local.key -out home.local.csr
  • -key – this option provides the private key for signing a new certificate or certificate request.

If you are wondering about the challenge password, here's a great answer on Server Fault explaining that "the "challenge password" requested as part of the CSR generation is not the same thing as a passphrase used to encrypt the secret key":

Expected output:

  • A file named home.local.csr with the first line -----BEGIN CERTIFICATE REQUEST-----.
5. Create an X509 V3 certificate extension config file

Create a file home.local.ext with the following content:

authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = *.home.local
6. Sign the certificate with the config
openssl x509 -req -in home.local.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out home.local.crt -days 1825 -sha256 -extfile home.local.ext

openssl x509 is the certificate display and signing command:

  • -req – by default a certificate is expected on input. With this option, a PKCS#10 certificate request is expected instead, which must be correctly self-signed.
  • -in home.local.csr – specifies the input to read a certificate from or the input file for reading a certificate request if the -req flag is used. In both cases, this defaults to standard input.
  • -CA ca.pem – specifies the "CA" certificate to be used for signing.
  • -CAkey ca.key – sets the CA private key to sign a certificate with.
  • -CAcreateserial – with this option and the -CA option, the CA serial number file is created if it does not exist. A random number is generated, used for the certificate, and saved into the serial number file determined as described above.
  • -out home.local.crt – specifies the output filename to write to or standard output by default.
  • -days 1825 – the number of days until a newly generated certificate expires.
  • -extfile home.local.ext – configuration file containing certificate and request X.509 extensions to add.

Expected output:

  • A file home.local.crt with the first line -----BEGIN CERTIFICATE-----.

This is it.

Now, to use this certificate in Kubernetes, we can install it with the following YAML definition:

apiVersion: v1 kind: Secret metadata: name: home-crt type: data: ca.crt: >- {{ cat ca.pem | base64 }} tls.crt: >- {{ cat home.local.crt | base64 }} tls.key: >- {{ cat home.local.key | base64 }}

But this is a different story.