Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using easy rsa, how to automate client / server creation process

Tags:

bash

I use easy rsa (https://github.com/OpenVPN/easy-rsa) to build my tiny ca and its clients / servers. Since its just for learning purposes, I was thinking about doing some automatization. Normally I can create files needed by client typing:

./easyrsa build-client-full client

but what when I need ~ 500 different client files? cp its not what I want here.

I tried to write a little bash script to help myself out:

#!/bin/bash

clients=3
pass=randompass
capass=castrongpassword

for i in `seq 1 $clients`
do
    ./easyrsa build-client-full test$i $pass $pass $capass
done

But it simply 'does not work'. When I build my client files in terminal I have to give 2 client passwords and the ca password. The main problem is I dont know how on earth pass it within script - is that possible? My script gives me Ignoring unknown command option: as output.

like image 942
mirx Avatar asked Mar 14 '14 20:03

mirx


2 Answers

Update (2020-04-03)

There has been some changes to EasyRSA script since I wrote the first answer.

  • EasyRSA 3.0.6 (released 2019-02-02) added --passin and --passout options which correctly pass the options to OpenSSL as described in my original answer
  • EasyRSA 3.0.7 (released 2020-03-31) added the ability to supply the passwords through the EASYRSA_PASSIN and EASYRSA_PASSOUT environment variables

Example:

./easyrsa --passout=file:passfile --passin=file:capassfile build-client-full $cn

Original answer

Reading through the easyrsa source code, it seems that the build-client-full command only takes one argument: name. So, the error that you get is simply because it does not know what to do with the passwords you have added on the command line. I guess that the program asks you for these passwords interactively, so you must supply them to the program via stdin.

Hacking easyrsa

NOTE: OpenSSL (the backend of easyrsa) does not listen to stdin by default. To make it do so, we must add "-passout stdin" (since it is a password saved in an output file) to the OpenSSL command line. Alternatively, one could add "-passout file:passfile" if the passwords are kept in the file passfile. To make it harder, easyrsa does not have an easy way of adding arguments to the OpenSSL command. Thus, we must change the source code somehow. However, this is easy.

To be able to use the alternatives below, add this into the gen_req function of easyrsa after the definition of local opts=:

gen_req() {
    ....
    local opts=
    opts="-passout stdin" # ADD THIS LINE
    # Alternatively: opts="-passout file:passfile"
    ....
}

Also, it seems that OpenSSL closes the stdin stream after its first use (in gen_req), so it can't also be used for signing with the CA certificate (in sign_req). We can tell OpenSSL to read from a file instead of reading from stdin (it may also be used for the above)

sign_req() {
    local crt_type="$1" opts=
    opts="-passin file:capassfile" # ADD THIS LINE (also: create capassfile)
    ...
}

(NOTE: The solutions below are kept mostly for future reference, in cases where multiple calls to OpenSSL is not involved...)

"General solution" #1: Pipes

One way to pass passwords through stdin is to start a subshell and then pipe it to easyrsa, which would simulate the actual keypresses you would have done manually. Your example would then look like this:

#!/bin/bash

clients=3
pass=randompass
#capass=castrongpassword   # (create the file 'capassfile' instead)

for i in `seq 1 $clients`
do
    (echo $pass; echo $pass) | ./easyrsa build-client-full test$i
done

Instead of creating a subshell, you could change the (echo $pass; echo ...) to

printf '%s\n' $pass $pass | ./easyrsa build-client-full test$i

or

echo -e "$pass\n$pass" | ./easyrsa build-client-full test$i

depending on what you find the most readable.

"General solution" #2: stdin redirection

The above alternative has the drawback that the passwords will appear in process listings (such as ps), and is thus from a security standpoint a bad idea if you are on a shared box. A better way would to create a file with the passwords, like this:

randompass
randompass

Then, you invoke easyrsa in your loop above by simply writing:

...
for i in `seq 1 $clients`
do
    ./easyrsa build-client-full test$i <passfile
done

where passfile is your file with the passwords. This of course assumes that you have the same password for all files.

like image 60
Joskar Avatar answered Oct 02 '22 07:10

Joskar


With a few steps and with openssl 1.1.1h& easyrsa3, I tried a similar solution which allows option -passin stdin and/or -passout file:passfile

  1. hardcode the option at function sign_req() line #834 in file easy-rsa/easyrsa3/easyrsa. change opts="" to opts="-passin stdin"

  2. use this function to create cert a single client,

    #function gen_full_client
    
    gen_full_client() { 
         CN=$1
         OVERWRITE=$2
    
     #Generate client using cn and sign it
     if [ -f "$EASYRSA_DIR/pki/private/$CN.key" ]; then         
         cat <<-EOF  | sudo $EASYRSA gen-req $CN nopass         
         $OVERWRITE
         $CN   
         EOF
     else
         cat <<-EOF  | sudo $EASYRSA gen-req $CN nopass         
         $CN   
         EOF
     fi
    
     #give it some time
     sleep 2
     CA_PASSWORD=$3
     #Generate client using cn and sign it
     if [ -f "$EASYRSA_DIR/pki/private/$CN.key" ]; then    
         #cat    <<-EOF | sudo $EASYRSA opts="-passout stdin" build-client-full $CN      
         cat <<-EOF   | sudo $EASYRSA sign-req client $CN 
         yes
         $(echo $CA_PASSWORD)
         EOF
     fi
    
     }
    

a simple call would create a single client entry

gen_full_client $1 $2 "$3"

iterate it over your for loop with passwords and pass it to the function and voila! It's done.

for i in `seq 1 $clients`
do
    gen_full_client test$i $pass $pass $capass
done
like image 41
Arun Panneerselvam Avatar answered Oct 02 '22 06:10

Arun Panneerselvam