Originally published February 21, 2020 @ 9:02 am

I’ve touched on this subject previously, but suddenly felt I should repeat myself. The big issue with using passwords from command line is shell history.

Regardless of how careful you are, eventually you’ll enter a password in clear text in your terminal session. It will then end up in your shell history; very likely in the system log; probably on some remote syslog collector; possibly in some log management application like Splunk or Graylog; and, of course, in backups of all of the above.

When this happens and you’re fortunate enough to realize it, the responsible thing to do would be to change the password immediately. Unfortunately, as sysadmins we often work with service accounts. More often than not, such accounts have non-expiring passwords.

These passwords may be changed from time to time, but such a change is usually a scheduled activity involving multiple teams and carrying a possibility of a production outage. I know this may sound archaic, but only to people not familiar with how large corporate IT works.

This password might have been around for years, tucked away in some script or a batch job that everyone forgot about and that powers your company’s entire business. And the guy who wrote it was last seen alive in New Zealand in the nineties (true story).

So the idea is simple: put the important password inside a plain text file. Use GPG to encrypt the file and delete the original. Now to get the real password, you need the GPG password to decrypt this file.

Should the GPG password escape into the wild, no big deal: delete the encrypted file containing the important password and recreate it with a new GPG password. No need to change the atomic password. Probably.

I know, this is not brilliant, but it’s a hell of a lot better than nothing. GPG is probably already installed but, if not, just yum install gpg or apt install gpg. All you need to do now is:

sudo apt-get install secure-delete gpg -y
gpg --symmetric ${password_file}
srm ${password_file}

# You will be prompted for the encryption password. Don't forget it.

And recalling the password is not difficult either:

read -s encryption_password
important_password="$(gpg --batch --decrypt \
--passphrase "${encryption_password}" \
-z 2 ${password_file} 2>/dev/null)"

Now the important password can be recalled as "${important_password}" in whatever script. Should some dumbass leak the encryption password, all you have to do is srm (secure rm) the encrypted file containing the important password and create a new one. It is unlikely there will be any need to change the important password.

So what else can we do with this? Well, this happens often to me: I log into some server and need to run a command that requires a password, an API key, an account number – something that is both sensitive and cannot be easily memorized. It would be nice to store this data in a file on the server for easy access. And many do just that, hoping that 400 permissions on that file is good enough security.

But there is a better way. Create a file in your home directory called, say, ~/.xconf containing “secret” variables and values. Pick a different field separator if ^ does not work for you:

#VAR^VALUE
api_code^5672hghjgcv34892767
api_secret^ghjkfd987656fgdfs6#$kjhdh
xusername^igor001
xpass^fghjKJHGF@#[L

Now you need to encrypt this file and get rid of the original:

read -s -t 10 xpasswd
# enter your secure password

gpg --batch --symmetric --quiet --yes \
--passphrase "${xpasswd}" ~/.xconf 2>/dev/null && \
shred -zvu -n 5 ~/.xconf 2>/dev/null 1>&2

chmod 400 ~/.xconf.pgp

The following lines you can either add to your ~/.bashrc or just put them in a script in your home folder, if you don’t want to set the variables every time you log in:

read -s -t 10 xpasswd
if [ ! -z "${xpasswd}" ] && [ -r ~/.xconf.gpg ]
then
  xconf="$(gpg --batch --decrypt --passphrase "${xpasswd}" -z 2 ~/.xconf.gpg 2>/dev/null)"
  IFS=$'\n'
  array_variables=($(echo "${xconf}" | grep -v '^#' | awk -F'^' '{print $1}'))
  array_defaults=($(echo "${xconf}" | grep -v '^#' | awk -F'^' '{print $2}'))
  unset IFS
  unset xconf
  for ((i = 0; i < ${#array_variables[@]}; i++))
  do
    if [ -z "$(eval echo $(echo $`eval echo "${array_variables[$i]}"`))" ]
    then
      eval "$(echo "${array_variables[$i]}")"="$(echo "\"${array_defaults[$i]}\"")"
    fi
  done
fi

This will momentarily decrypt the ~/.xconf.pgp and assign values to the corresponding variables:

echo $api_code $api_secret $xusername $xpass

5672hghjgcv34892767 ghjkfd987656fgdfs6# igor001 fghjKJHGF@#[L

So now you have all this data handy without ever having to type any of it and risk exposing sensitive information from command line.