ar_doc_33 openssl_ECC_enc_dec_signature - JohnHau/mis GitHub Wiki
Shell script to generate certificate OpenSSL [No Prompts] Table of Contents Sample shell script to generate self-signed certificate Steps involved to generate self-signed certificate Create configuration file Prepare shell script to generate certificate How this script works? Verify the script execution Sample shell script to generate RootCA and server certificate Steps involved to generate RootCA and server certificate Create configuration file for RootCA certificate Create configuration file for server certificate Create Extension and SAN file for server certificate Prepare shell script to generate certificate How this script works? Verify the script execution Summary 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:
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:
[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:
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 Our certificates will be stored inside /certs We have a function to print the help section as show_usage 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. If the user executes the script without any argument, the script will use the system's hostname as Common Name 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
[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 ](/JohnHau/mis/wiki/-!--f-$CA_KEY-);then
$OPENSSL_CMD genrsa -out $CA_KEY 4096 2>/dev/null
[ $? -ne 0 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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 ](/JohnHau/mis/wiki/-$?--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.
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:
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.