Automating easy-rsa cert creation with Bash script In order to make cert creation with easy-rsa as practical for others, this script was created and it works so far.  The questions are:


where can it be improved?
are there flaws that are not obvious to the author?


The commentary is a bit extensive, but whomever will come across this in the future should be able to understand what's being done no matter how advanced.

#!/bin/bash
##
## This script automates the complete process of creating new easy-rsa  client certificates.
## It includes:     1. Mounting a block device.
##          2. Generating certificates using individual timestamps.
##          3. Copying the created certs to the mounted block device.
##
##
#
# First we look for the usb device at sdc1 and mount it. If not present tell the pebcac the it should insert one.


# all the predifined variables will end up beneath

myself=auto_rsa_gen.sh # tells the script who it is

export easy_rsa=../rsa_testing # tells the script where it is and exports this information for use in child processes


now=$(date +"%F")


##
# Show a list of available drives and ask the user for the dev he wants to mount
echo "These \n$(ls /dev | grep sd) \nare the drives available. Please tell me which one you want to mount \n(hint: its usually the one having just the  one additional entry. Like sdc1):"

# read user input (blkdev is the variable that will hold the user inuput for further processing)
read blkdev

##
# I. Mount
# check if de given device exists
if [ -b /dev/"$blkdev" ]
        then # if it exists mount it to /media
            sudo mount /dev/$blkdev /media
            echo "\nDevice $blkdev has been mounted!"
        else # if it doesn't exist
            echo "Device doesn't appear to exist! Restarting"
            sh "$myself" # restart the script
        fi

# Ask for an identifier to be used in the wrapper for easy-rsa cert creation
echo "\nPlease provide an identifier for the certs that will be created \n(The identifier will be appended to the current date of the machine):"

# read user input (ident is the variable that will hold the user input for further processing)
read ident

# Ask for ne number of certs to be created
echo "\nHow many certificates do you want me to create?"
# read user input (cnum is the variable that will hold the user input for further processing)
read cnum

##
# II. Wrapper for easy-rsa cert creation
#

# this is a while loop in case there was no input for ident. It only stop when the user hast put in something other than nothing
while [ -z $ident ]
    do
    echo "\nYou did not supply an identifier. Please do so or i will terminate."
    read ident # read user input again
done

# change directory to the easy-rsa directory
cd $easy_rsa

# tell user what you are going to do
echo "\nCreating $cnum certificates with ${now}_$ident."

# load vars file
. ./vars

##
# II.a Generation
# for loop that creates $cnum certificates and appends an incrementing number to the end of every
# file name

for i in $(seq -f %03g $cnum)
    do
        ${easy_rsa}/./build-batch ${now}_${ident}_$i

done

##
# II.b Copying
# for loop that searches for all certs created with this run and copies them to /media where $blkdev is mounted
find ${easy_rsa}/keys/ -name ${now}_${ident}*.crt -o -name ${now}_${ident}*.key &gt; /media/${now}_${ident}
for f in $(find ${easy_rsa}/keys/ -name ${now}_${ident}*.crt -o -name ${now}_${ident}*.key )
    do
        cp $f /media

done
echo "\nCopied \n$(find ${easy_rsa}/keys/ -name ${now}_${ident}*.crt -o -name ${now}_${ident}*.key) \nto /media"

# unmounting $blkdev at /media
umount /media
echo "\nUmounted $blkdev at /media. Exiting! Bye!"ere
This

myself=auto_rsa_gen.sh # tells the script who it is


is better done like this:

myself="$0"


or, if you want just filename, then

myself="$(basename "$0")"


because it will give you the actual name of the script, instead of being hard-coded. This also opens a nice renaming possibilities if you use symlinks.

This part:

echo "These \n$(ls /dev | grep sd) \nare the drives available. Please tell me which one you want to mount \n(hint: its usually the one having just the  one additional entry. Like sdc1):"

# read user input (blkdev is the variable that will hold the user inuput for further processing)
read blkdev

##
# I. Mount
# check if de given device exists
if [ -b /dev/"$blkdev" ]
        then # if it exists mount it to /media
            sudo mount /dev/$blkdev /media
            echo "\nDevice $blkdev has been mounted!"
        else # if it doesn't exist
            echo "Device doesn't appear to exist! Restarting"
            sh "$myself" # restart the script
        fi


I think is better put in a while loop, instead of restarting a script, like this:

while true; do
  echo "Pick device, blah, blah,... Press Ctrl+C to abort."
  read blkdev
  if [ ! -b /dev/"$blkdev" ]; then
    echo "The device doesn't appear to exist!"
    continue;
  fi
  sudo mount /dev/"$blkdev" /media
  echo "\nDevice '$blkdev' has been mounted!"
done


You might also want to check if the mount command succeeded.

Also, /media is a standard directory for dynamic mounts. That means that your script will hide mountpoints of mounted CDs, DVDs, USB keys,... while it is running, which may be very inconvenient in some situations (for example, if you have some copying done in the background).

Btw, echo 'Line 1\nLine 2' outputs Line 1\nLine 2 instead of two lines (GNU bash, version 4.2.45, Fedora 19). The correct way for this is

echo -e 'Line 1\nLine 2'


I assume you have -e aliased, or on your distribution it is on by default, or something like that. However, it is not portable, so I suggest you add -e where needed.

I also have a bit of a problem with

cd $easy_rsa


These are my concerns:


It has a relative path to the subdirectory. This will hardly produce satisfactory results if your script is invoked from a directory other than you intended it to be invoked from. Maybe this value should either be prompted (with read), or picked up from the command line?
You're not checking that the directory exists. You could force the directory creation (mkdir -p "$easy_rsa"), and - on top of that - check that $0 is true (i.e., equal to 0) afterwards.


In the last line

echo "\nUmounted $blkdev at /media. Exiting! Bye!"ere


This ere in the end seems to be here by an error.

I also have one general remark. Instead of writing echo $something, cd $dir, and similar commands, I suggest you use echo "$something", cd "$dir", etc. There is no point in thinking if one of these may contain space and, when editing your script later on, thinking about fixing this if you do include a space. It's much easier and safer to always behave as if a variable can contain a space and just include the quotation marks.

Also, without the quotation marks, you're in trouble with all the variables that get their values from the user. The example for this is your $blkdev variable which you sometimes enclose in the quotation marks, but sometimes you do not (I added them in the mount command in my loop example above).