Simple bash variable security with OpenSSL
Lets say you have a script that requires a number of variables to operate such as a database connection that requires a server, username and password. It’s usually a good idea to keep all this config in one place but dumping this in a plain text file is usually a bad idea.
The example below allows you to place application level config into a decently encrypted file and keep it all behind one master password.
To do all this we need two files. The first is obviously the encrypted variable config itself. The second is your script file which needs to decrypt the config file and perform whatever action is needed.
In this example I’m going to assume we are connecting to a remote database. Most protocols require three pieces of data to pull this off: a server, a username and a password. We are going to store these three pieces of data in a file called config.plain, encrypt this file (making config.aes), extract its variables and finally connect to our remote database.
I’m going to use the following example config.plain file:
SERVER=FooBar USER=JOE PASS=RANDOM
So we need to encrypt our config.plain file and turn it into config.aes (AES being the encryption standard we are using). The following example is cheerfully swiped from the example given over at Tombuntu.
>openssl aes-256-cbc -a -salt -in config.plain -out config.aes
So if we wanted to reverse this and decrypt the config.aes file on the command line we could run:
>openssl aes-256-cbc -d -a -salt -in config.aes
NOTE: For some reason the OpenSSL CLI doesn’t obey the Unix standard of specifying ‘-’ as a file name to output to the console. Omitting the ‘-out’ argument will instead output to STDOUT.
Putting it all together
The config.plain example file:
SERVER=FooBar USER=JOE PASS=RANDOM
The config.aes file (same as above but after encryption using the password ‘password’):
The actual script file which does the decryption and performs the final actions on the data.
We are going to accept the master password from the command line (so we would run the below as ‘script password’ – assuming our script was called ‘script’ and the password was ‘password’). This is not the most secure method available since you can see the launch method of all applications running on the system using ‘ps’. If you want more security I would instead store your password in a system variable and use that instead of reading from the command line. If you wish to do this you can simply strip out all the lines that do error checking and use ‘KEY’ as a system variable to store the master password.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#!/bin/bash # USAGE: script <password> # Do something with the associated config.aes script in a reasonably secure way # # Example config.plain content: # SERVER=FooBar # USER=JOE # PASS=RANDOM # # Command to encrypt config.plain -> config.aes # openssl aes-256-cbc -a -salt -in config.plain -out config.aes # Do some housekeeping to check we launched with the requisite number of arguments if [ "$#" -ne 1 ]; then echo "USAGE: $0 <password>" exit 1 fi KEY="$1" # Import the variables from our decrypted stream STREAM=`openssl aes-256-cbc -d -pass "pass:$KEY" -a -salt -in config.aes` if [ "$?" -ne 0 ]; then echo "Invalid password specified to decrypt configuration file. Aborting." exit 1 fi source <(echo "$STREAM") # REPLACE THE STUFF BELOW THIS LINE WITH WHAT YOU WANT TO DO WITH YOUR SECURE VARIABLES echo "Server: $SERVER" echo "Username: $USER" echo "Password: $PASS"