Shell script to generate certificate OpenSSL [No Prompts]

In this tutorial we will write a shell script to generate certificates using openssl command. The idea is to have a procedure to generate certificates without any additional prompt. Normally in the process of generating certificates, there are a number of prompts, especially while generating Certificate Signing Request. But when we plan to automate this process then we cannot expect user to provide these prompts every time we need a certificate.

So we will cover following two scenarios to generate certificate without any prompt using shell script:

Advertisement
  • Use shell script to generate self-signed certificate
  • Use shell script to generate RootCA and RootCA signed certificate

 

Sample shell script to generate self-signed certificate

Steps involved to generate self-signed certificate

Before you go to the script, you should be familiar with the steps involved in generating any self signed certificate:

  • Generate private key
  • Generate certificate Signing Request
  • Generate self signed certificate

Now in these steps, manual intervention is required for generating CSR. So we basically want to automate this part in our script.

 

Create configuration file

We can prepare a configuration file which we can use to auto-populate the CSR generation process. Normally we get a prompt for the following question:

  • countryName
  • stateOrProvinceName
  • localityName
  • organizationName
  • commonName

So we will pre-define these fields in our configuration file which will be provided as an input to the openssl command while generating the CSR file.

Now assuming you plan to generate self-signed certificate for 100s of servers. In such case all the above fields can be same for all the servers but commonName must be unique for all the servers. So we must make this as an input argument to the script or handle this internally.

We will explain this part in the script. But for now let us add some value to remaining fields in the above configuration file:

Advertisement
[root@controller certs]# cat cert_ext.cnf
[req]
default_bit = 4096
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
countryName             = IN
stateOrProvinceName     = Karnataka
localityName            = Bengaluru
organizationName        = GoLinuxCloud

So, we have provided the distinguished_name as the preferred section to look out for CSR details. Additionally we have defined a default bit size to be used for generating the certificate. This is optional and you can also define this as an input to openssl command.

The important part is prompt = no, so the openssl command will not prompt for anything, instead it will fetch all the values from req_distinguished_name section.

 

Prepare shell script to generate certificate

Here I have a sample script which can be used to generate self-signed certificate. Now this is a very basic script which you can modify and use based on your requirement.

[root@controller certs]# cat gen_certificates.sh

Sample Output

PATH="/certs"
SERVER_KEY="$PATH/server.key"
SERVER_CSR="$PATH/server.csr"
SERVER_CRT="$PATH/server.crt"
EXTFILE="$PATH/cert_ext.cnf"
OPENSSL_CMD="/usr/bin/openssl"
COMMON_NAME="$1"

function show_usage {
    printf "Usage: $0 [options [parameters]]\n"
    printf "\n"
    printf "Options:\n"
    printf " -cn, Provide Common Name for the certificate\n"
    printf " -h|--help, print help section\n"

    return 0
}

case $1 in
     -cn)
         shift
         COMMON_NAME="$1"
         ;;
     --help|-h)
         show_usage
         exit 0
         ;;
     *)
        ## Use hostname as Common Name
        COMMON_NAME=`/usr/bin/hostname`
        ;;
esac

# generating server key
echo "Generating private key"
$OPENSSL_CMD genrsa -out $SERVER_KEY  4096 2>/dev/null
if [ $? -ne 0 ] ; then
   echo "ERROR: Failed to generate $SERVER_KEY"
   exit 1
fi

## Update Common Name in External File
/bin/echo "commonName              = $COMMON_NAME" >> $EXTFILE

# Generating Certificate Signing Request using config file
echo "Generating Certificate Signing Request"
$OPENSSL_CMD req -new -key $SERVER_KEY -out $SERVER_CSR -config $EXTFILE 2>/dev/null
if [ $? -ne 0 ] ; then
   echo "ERROR: Failed to generate $SERVER_CSR"
   exit 1
fi


echo "Generating self signed certificate"
$OPENSSL_CMD x509 -req -days 3650 -in $SERVER_CSR -signkey $SERVER_KEY -out $SERVER_CRT 2>/dev/null
if [ $? -ne 0 ] ; then
   echo "ERROR: Failed to generate self-signed certificate file $SERVER_CRT"
fi

 

How this script works?

Here the flow of our script:

  1. We have defined variables for all the certificate, private key, external file and any other files which we will use across the script. This is recommended to avoid using file names
  2. Our certificates will be stored inside /certs
  3. We have a function to print the help section as show_usage
  4. We have a parse function to process the input argument. If the end user decides to provide the commonName then they can execute the script with -cn argument followed by the Common Name value.
  5. If the user executes the script without any argument, the script will use the system's hostname as Common Name
  6. Next we generate private key, followed by CSR and self-signed certificate

 

Verify the script execution

Provide executable permission to the script:

[root@controller certs]# chmod u+x gen_certificates.sh

Print the help section:

[root@controller certs]# ./gen_certificates.sh -h
Usage: ./gen_certificates.sh [options [parameters]]

Options:
 -cn, Provide Common Name for the certificate
 -h|--help, print help section

Let us execute the script to make sure it is working as expected

Advertisement
[root@controller certs]# ./gen_certificates.sh -cn test.example.com
Generating private key
Generating Certificate Signing Request
Generating self signed certificate

Verify the Common Name in the certificate:

[root@controller certs]# openssl x509 -noout -text -in server.crt  | grep Subject
        Subject: C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, CN = test.example.com
        Subject Public Key Info:

Now let us execute the script without any argument:

[root@controller certs]# ./gen_certificates.sh
Generating private key
Generating Certificate Signing Request
Generating self signed certificate

Verify the Common Name section:

[root@controller certs]# openssl x509 -noout -text -in server.crt  | grep Subject
        Subject: C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, CN = controller.example.com
        Subject Public Key Info:

 

Sample shell script to generate RootCA and server certificate

In this section we will prepare a shell script to generate RootCA certificate and then use this RootCA certificate to further create and sign a server certificate. later we can use this server certificate with our applications.

 

Steps involved to generate RootCA and server certificate

First let us understand the steps involved in generating a RootCA certificate and then using this RootCA to sign a server certificate.

  • Generate RootCA private key
  • Generate RootCA certificate
  • Generate server private key
  • Generate CSR for server certificate
  • Generate server certificate and sign using RootCA

Here manual intervention is required while generating rootCA certificate and while generating CSR for server certificate. So we basically need two configuration files to automate this process.

 

Create configuration file for RootCA certificate

Here is the sample output of my configuration file which I will use to generate RootCA certificate:

[root@controller certs]# cat ca_cert.cnf
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no

[req_distinguished_name]
countryName             = IN
stateOrProvinceName     = Karnataka
localityName            = Bengaluru
organizationName        = GoLinuxCloud
commonName              = rootca.com

[ v3_ca ]
basicConstraints=critical,CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer

As you can see I have defined multiple sections in the configuration file.

  • [req]:  field is basically mapping different sections which should be checked for respective configuration option
  • [ req_distinguished_name]:  contains the details to be used while generating the CSR for the RootCA certificate. Since we have defined prompt = no, the openssl command will collect the details from the configuration file without any prompt.
  • [v3_ca]: field contains the X.509 extensions to be used for the RootCA certificate. Since this is a CA certificate, we have marked CA:TRUE
  • authorityKeyIdentifier: The Authority Key Identifier extension identifies the public key corresponding to the private key used to sign a certificate. This extension is useful when an issuer has multiple signing keys, such as when a CA certificate is renewed.
  • subjectKeyIdentifier: The Subject Key Identifier extension identifies the public key certified by this certificate. This extension provides a way of distinguishing public keys if more than one is available for a given subject name.

 

Create configuration file for server certificate

Here is my sample configuration file which I intend to use to generate my server certificate.

[root@controller certs]# cat server_cert.cnf
default_bit = 4096
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
countryName             = IN
stateOrProvinceName     = Karnataka
localityName            = Bengaluru
organizationName        = GoLinuxCloud
commonName              = example.com

These fields are already explained in the RootCA section.

 

Create Extension and SAN file for server certificate

We will also need one external file to provide the X.509 extensions and SAN details. Here is my sample external file:

[root@controller certs]# cat server_ext.cnf
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.12.100
IP.2 = 192.168.11.101
IP.3 = 192.168.10.102
DNS.1 = node-1.example.com
DNS.2 = node-2.example.com

Some of the sections are already explained under rootCA configuration file option. Let me cover the remaining section:

  • KeyUsage: Defines the purpose of a key in a certificate.
  • extKeyUsage: The Extended Key Usage extension indicates the purposes for which the certified public key may be used. We will use this as both server and client certificate.
  • [alt_names]: This is the Subject Alternative Name (SAN) field. This is an optional section. You can follow the same approach as we used with self-signed certificate to use Common Name. But in server client certificates, we normally prefer using SAN so that we can use single certificate for multiple servers rather than creating one for each server. Here I have defined a number of IP and DNS value which we will assign to our server certificate.
    You can read more at Create san certificate | openssl generate csr with san command line

 

Prepare shell script to generate certificate

Here is my sample shell script to generate certificate for RootCA and server:

[root@controller certs]# cat gen_certificates.sh

Sample Output:

#!/bin/bash

PATH="/certs"
SERVER_KEY="$PATH/server.key"
SERVER_CSR="$PATH/server.csr"
SERVER_CRT="$PATH/server.crt"
CA_KEY="$PATH/ca.key"
CA_CRT="$PATH/cacert.pem"
CA_EXTFILE="$PATH/ca_cert.cnf"
SERVER_EXT="$PATH/server_cert.cnf"
SERVER_CONF="$PATH/server_cert.cnf"
OPENSSL_CMD="/usr/bin/openssl"
COMMON_NAME="$1"

function generate_root_ca {

    ## generate rootCA private key
    echo "Generating RootCA private key"
    if [[ ! -f $CA_KEY ]];then
       $OPENSSL_CMD genrsa -out $CA_KEY 4096 2>/dev/null
       [[ $? -ne 0 ]] && echo "ERROR: Failed to generate $CA_KEY" && exit 1
    else
       echo "$CA_KEY seems to be already generated, skipping the generation of RootCA certificate"
       return 0
    fi

    ## generate rootCA certificate
    echo "Generating RootCA certificate"
    $OPENSSL_CMD req -new -x509 -days 3650 -config $CA_EXTFILE -key $CA_KEY -out $CA_CRT 2>/dev/null
    [[ $? -ne 0 ]] && echo "ERROR: Failed to generate $CA_CRT" && exit 1

    ## read the certificate
    echo "Verify RootCA certificate"
    $OPENSSL_CMD  x509 -noout -text -in $CA_CRT >/dev/null 2>&1
    [[ $? -ne 0 ]] && echo "ERROR: Failed to read $CA_CRT" && exit 1
}

function generate_server_certificate {

    echo "Generating server private key"
    $OPENSSL_CMD genrsa -out $SERVER_KEY 4096 2>/dev/null
    [[ $? -ne 0 ]] && echo "ERROR: Failed to generate $SERVER_KEY" && exit 1

    echo "Generating certificate signing request for server"
    $OPENSSL_CMD req -new -key $SERVER_KEY -out $SERVER_CSR -config $SERVER_CONF 2>/dev/null
    [[ $? -ne 0 ]] && echo "ERROR: Failed to generate $SERVER_CSR" && exit 1

    echo "Generating RootCA signed server certificate"
    $OPENSSL_CMD x509 -req -in $SERVER_CSR -CA $CA_CRT -CAkey $CA_KEY -out $SERVER_CRT -CAcreateserial -days 365 -sha512 -extfile $SERVER_EXT 2>/dev/null
    [[ $? -ne 0 ]] && echo "ERROR: Failed to generate $SERVER_CRT" && exit 1

    echo "Verifying the server certificate against RootCA"
    $OPENSSL_CMD verify -CAfile $CA_CRT $SERVER_CRT >/dev/null 2>&1
     [[ $? -ne 0 ]] && echo "ERROR: Failed to verify $SERVER_CRT against $CA_CRT" && exit 1

}

# MAIN
generate_root_ca
generate_server_certificate

In this example, we have removed the help and parse section compared to the one which I used to generate self-signed certificates

 

How this script works?

Let us understand the functions of this script:

  • First of all I have defined a couple of variables to declare different types of file which we will use thorugh out the process
  • Our certificates will be generated and stored under /certs folder
  • I have created two functions separately to generate RootCA certificate and server certificate
  • If a rootCA private key already exists then the script will skip the generation of rootCA certificate and continue with the generation of server certificate
  • The rest of the script is using different openssl command to generate and verify respective private keys and certificates

 

Verify the script execution

Provide executable permission to the script:

[root@controller certs]# chmod u+x gen_certificates.sh

Let us execute the script and make sure it is working as expected:

[root@controller certs]# ./gen_certificates.sh
Generating RootCA private key
Generating RootCA certificate
Verify RootCA certificate
Generating server private key
Generating certificate signing request for server
Generating RootCA signed server certificate
Verifying the server certificate against RootCA

As expected, our script has successfully generated both rootCA and server certificate.

Shell script to generate certificate OpenSSL [Without prompt]

Let us re-run the script:

[root@controller certs]# ./gen_certificates.sh
Generating RootCA private key
/certs/ca.key seems to be already generated, skipping the generation of RootCA certificate
Generating server private key
Generating certificate signing request for server
Generating RootCA signed certificate
Verifying the server certificate against RootCA

As expected, the script has skipped the generation of rootCA certificate as the CA key from our last execution was still available:

Shell script to generate certificate OpenSSL [Without prompt]

Verify the SAN details from the server certificate:

[root@controller certs]# openssl x509 -noout -text -in server.crt | grep -A 1 "Subject Alternative"
            X509v3 Subject Alternative Name:
                IP Address:192.168.12.100, IP Address:192.168.11.101, IP Address:192.168.10.102, DNS:node-1.example.com, DNS:node-2.example.com

 

Summary

In this tutorial I explained how we can use shell script to generate certificate using OpenSSL. I covered two scenarios where you can generate either a self-signed certificate or rootCA signed server certificate.

The scripts shared in this tutorial are very simple and does not cover multiple negative scenarios, you may adapt this script further as per your requirements.

Let me know if you have any questions or feedbacks using the comments section.

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment