How to securely work with private keys in a bash script? My first attempt involves storing the encrypted key pair in a field in the database(mongo). However, I've since realised that I will have to use these keys in bash scripts, after being decrypted, in order to scp or ssh(key has to be a file so this will also increase IO).
This occurs inside an alpine linux container. Should I be concerned about using echo
on a string containing a key?
I've also considered storing the keys in a container volume as files (id_rsa, id_rsa.pub) and referencing those paths in the database(or hardcoding a path). I am working with very many key pairs which go from DB to UI to API(3 separate containers) to BASH(in the API container)to create a connection and perform functions on each of these hosts. Which helps with the IO problem.
Is there a better way to do this? Should I be using some sort of keystore that I can store references for inside my DB?
In order of importance, Secure - Low IO - High Efficiency.
Thanks @Philippe for suggesting the use of PGP! My solution is:
Create a master key using this script:
#!/bin/bash
cd ~/
mv .gnupg .gnupg.bak
echo "Existing keys were moved to '.gnupg.bak'."
# rm -rf .gnupg
mkdir -m 0700 .gnupg
touch .gnupg/gpg.conf
chmod 600 .gnupg/gpg.conf
echo << EOF > .gnupg/gpg.conf
################################################################################
# GnuPG Options
# (OpenPGP-Configuration-Options)
# Assume that command line arguments are given as UTF8 strings.
utf8-strings
# (OpenPGP-Protocol-Options)
# Set the list of personal digest/cipher/compression preferences. This allows
# the user to safely override the algorithm chosen by the recipient key
# preferences, as GPG will only select an algorithm that is usable by all
# recipients.
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
personal-cipher-preferences AES256 AES192 AES CAST5 CAMELLIA192 BLOWFISH TWOFISH CAMELLIA128 3DES
personal-compress-preferences ZLIB BZIP2 ZIP
# Set the list of default preferences to string. This preference list is used
# for new keys and becomes the default for "setpref" in the edit menu.
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
# (OpenPGP-Esoteric-Options)
# Use name as the message digest algorithm used when signing a key. Running the
# program with the command --version yields a list of supported algorithms. Be
# aware that if you choose an algorithm that GnuPG supports but other OpenPGP
# implementations do not, then some users will not be able to use the key
# signatures you make, or quite possibly your entire key.
#
# SHA-1 is the only algorithm specified for OpenPGP V4. By changing the
# cert-digest-algo, the OpenPGP V4 specification is not met but with even
# GnuPG 1.4.10 (release 2009) supporting SHA-2 algorithm, this should be safe.
# Source: https://tools.ietf.org/html/rfc4880#section-12.2
cert-digest-algo SHA512
digest-algo SHA256
# Selects how passphrases for symmetric encryption are mangled. 3 (the default)
# iterates the whole process a number of times (see --s2k-count).
s2k-mode 3
# (OpenPGP-Protocol-Options)
# Use name as the cipher algorithm for symmetric encryption with a passphrase
# if --personal-cipher-preferences and --cipher-algo are not given. The
# default is AES-128.
s2k-cipher-algo AES256
# (OpenPGP-Protocol-Options)
# Use name as the digest algorithm used to mangle the passphrases for symmetric
# encryption. The default is SHA-1.
s2k-digest-algo SHA512
# (OpenPGP-Protocol-Options)
# Specify how many times the passphrases mangling for symmetric encryption is
# repeated. This value may range between 1024 and 65011712 inclusive. The
# default is inquired from gpg-agent. Note that not all values in the
# 1024-65011712 range are legal and if an illegal value is selected, GnuPG will
# round up to the nearest legal value. This option is only meaningful if
# --s2k-mode is set to the default of 3.
s2k-count 1015808
################################################################################
# GnuPG View Options
# Select how to display key IDs. "long" is the more accurate (but less
# convenient) 16-character key ID. Add an "0x" to include an "0x" at the
# beginning of the key ID.
keyid-format 0xlong
# List all keys with their fingerprints. This is the same output as --list-keys
# but with the additional output of a line with the fingerprint. If this
# command is given twice, the fingerprints of all secondary keys are listed too.
with-fingerprint
with-fingerprint
# Use gpg-agent for SSH instead of ssh-agent
use-agent
EOF
cd .gnupg
cat >master <<EOF
%echo Generating Master PGP key
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Master
Name-Comment: Master
Name-Email: [email protected]
Expire-Date: 0
%no-ask-passphrase
%no-protection
%pubring pubring.kbx
%secring trustdb.gpg
%commit
EOF
gpg2 --verbose --no-greeting --batch --gen-key master
echo -e "5\ny\n" | gpg2 --command-fd 0 --expert --no-greeting --batch --edit-key [email protected] trust;
echo "Master key has been created and verified. :)" > TESTFILE
gpg2 -e -a -r [email protected] TESTFILE
rm TESTFILE
rm master
gpg2 -d TESTFILE.asc
rm TESTFILE.asc
Create sub keys using this script:
#!/bin/bash
echo -e "addkey\n8\nS\nA\nQ\n4096\n0\nsave" | gpg2 \
--command-fd 0 --verbose --no-greeting --expert --edit-key --batch --passphrase "" [email protected];
fingerprints=$(gpg2 --list-keys --with-subkey-fingerprint | grep " " | sed 's/ //g')
fingerprint=$(echo $fingerprints | awk '{print $NF}')
publicId=$(echo ${fingerprint: -8})
fingerprint=$(echo $fingerprints | awk '{print $1}')
privateId=$(echo ${fingerprint: -8})
echo "Using master key with ID:"
echo $privateId
echo "Sub key added with ID:"
echo $publicId
and storing the IDs printed from that last script in mongo, master as 'private' and sub as 'public'.
Sending public auth keys to remote hosts with gpg2 --export-secret-key $ID | ssh $REMOTE_MACHINE gpg2 --import