Storing Secrets
Get secrets out of code! Always avoid putting passwords, API keys, etc in your code, especially if your code is in git, and avoid storing them in plaintext. Never try to encrypt it yourself; danger lies this way. Always use a widely known and trusted tool that is specifically made for this purpose.
If you are running on a desktop system,
Use your keychain. This is secured by your login session, i.e. the username and password you use to login to your desktop.
If using python, see Storing Secrets in Python. The python code is identical regardless of which OS you’re using.
For keychain access on the command line:
MacOS
To access MacOS keychain from Terminal, here is a good guide:
Get Password from Keychain in Shell Scripts
Windows:
(to-do)
Linux (Gnome):
The gnome user keyring, also known as "Passwords and Keys," formerly called "Seahorse" password manager, can be accessed on the terminal:
Prerequisite for ubuntusudo apt install -y libsecret-tools
Prerequisite for RHEL 9sudo yum -y install libsecret
And then:
# Store Secret # You may use any key-value pairs you want to identify this secret. In this example, I'm using # "server myserver" and "user myuser". You could just as well use "bananas 23" and "car blue" if you # wanted. The keystore stores these as key-value pairs. The `lookup` command will print the secret # of whatever entry first matches all the key-value pairs specified. It is recommended you choose # key-value pairs which will uniquely identify your secret with no ambiguity if more than one secret # needs to be stored. Using `--label=` merely provides a user-friendly label that will appear in # the GUI Passwords and Keys. echo "secret" | secret-tool store --label='MyLabel' server myserver user myuser # Lookup Secret secret-tool lookup server myserver user myuser
If you are running without a desktop
Automated service accounts, cron jobs, etc, that don’t have access to a login session keychain can still be secured. Several approaches are possible. Use whichever you see fit.
The goal is to make a secret available to one process, and no other. This technique puts the secret into root’s home directory, and makes the secret available to only one process running under another user, via
sudo
,su
, andenv
. You could use a different directory if you wish, provided its permissions are adequately locked down.
/root/bin/launchmyapp.sh
/etc/sudoers.d/10_LAUNCHMYAPP
Now "someuser" can launch the app via sudo, and whencommand_to_run
runs, it will have the$SECRET
environment variable available. It is important that the commandcommand_to_run
should not be writable by the user. The only way the user can access this secret is via the sudo command, and if that command doesn't leak it, it's secure.Selinux / apparmor: In addition to permission bits, consider using selinux or apparmor to restrict access to just the application that needs it. These tools can make a file inaccessible except if a process is running in a particular context, and the only way to get into that context is by being launched by a particular parent process. Thus, your valid script launched your valid way will have access to the secret, whereas the same script running as the same user, launched by a compromised httpd process (or whatever) cannot. You may find this useful: SELinux.
Many users on the internet recommend using encryption via
pgp
,gpg
,pass
,openssl
, etc. If the secret is encrypted but the decryption key is equally available, it is snakeoil, fake security. It adds a layer of complexity and false sense of security. Tools such aspgp
andopenssl
are valuable for other purposes, but not this one. Don’t use fake encryption.If you cannot use the previous technique to move secrets into root’s home directory, store your secrets in a dedicated location, outside your code repository, so you don’t accidentally publish via
git push
or similar. Ensure the permissions are as locked down as possible. I repeat and emphasize, see the comments above, about selinux or apparmor.
Example: