DEV Community

Cover image for How to securely store API keys

How to securely store API keys

Bruno Pedro 💡 on October 26, 2017

In the past, I’ve seen many people use git repositories to store sensitive information related to their projects. Lately, I’ve also been seeing som...
Collapse
 
thatjoemoore profile image
Joseph Moore

If you're running in AWS, you can also make use of Parameter Store, which seems to fly under the radar for a lot of people (being buried three layers deep inside another product probably contributes to that). It allows you to set general configuration parameters, as well as secrets which are encrypted at rest using KMS. At my job, we're starting to use Parameter Store a lot, even when we're testing our applications locally. Our keys never have to live on our machines - as long as we're logged into the AWS CLI, our apps can access them in the same way they would in production.

Collapse
 
bpedro profile image
Bruno Pedro 💡

Hi Joseph. Thanks for sharing information about the AWS Parameter Store! I didn't know about it, and it certainly looks like a good solution.

Collapse
 
metcoder profile image
Carlos Fuentes

What about ignoring the .env file or any file you use to save your keys and secrets with .gitignore?

Collapse
 
willemw profile image
Willem Wollebrants

This is how I* do it: .env is ignored, and there's an .env.example included in the repository so that a developer knows which keys are expected/needed/available.

  • not just me, of course. Laravel for example has the same thing
Collapse
 
courier10pt profile image
Bob van Hoove

It's what we currently do at work. The secret files are in a KeePass database. It's cumbersome to deal with, especially when you want to checkout a fresh version of a project. Even with a script that copies the files to the projects that should contain them.

Ofcourse this has to do with KeePass as our solution for storing the .gitignored files.

I'm glad the author made the effort of listing some alternatives ways to protect files, and others responded with even more ways to do it. Because at some point I'll be fed up with that KeepAss database and this article is where I'll refer back to :)

Collapse
 
alanguir profile image
Alan Languirand

Environment variables are by far the simplest way to go. There’s a bit of initial coordination when multiple developers need the same keys - anyone have a favorite way to do initial setup?

Collapse
 
erebos-manannan profile image
Erebos Manannán

Salt Stack - a better alternative to Puppet, Chef, etc. - also comes with built-in support for encrypting secrets while you store them in your version control. Basic idea is simple:

  • You generate the public & private GPG keys on your Salt "master" -server
  • Those keys can be used to encrypt any values in Salt configuration (works on value-level, not just file-level)
  • You encrypt the environment's configuration with the environment's GPG keys
  • You store the encrypted secrets in version control
  • Only the Salt "master" server can decrypt them and release the values to various states and templates that you use to configure your servers

If not using something like Docker, then Salt is one of the best options out there for managing your server configuration (though in my opinion THE best), and supports this out of the box.

docs.saltstack.com/en/latest/ref/r...

Collapse
 
bpedro profile image
Bruno Pedro 💡

Hi Duke. Salt Stack looks very interesting. Thanks for sharing it—I'll add it to my list of alternatives.

Collapse
 
erebos-manannan profile image
Erebos Manannán

Yea it does a lot of things very well, and is built with components that you can take into use separately.

Some examples of things you can do with Salt Stack:

  • Configure your servers (install software, setup config files, restart services, yadi yadi yada)
  • Automate actions throughout your infrastructure based on events, e.g. when a new API server boots up it gets added to the load balancer
  • Orchestrate your cloud infrastructure - you configure the number of each type of server you need and Salt takes care of the rest
  • Remotely run shell commands on multiple servers simultaneously with filters
  • Do various rolling release fashion operations

Basically Salt Stack can take care of most of your server management needs.

Collapse
 
jasongabler profile image
Jason Gabler

Where do you store the encryption keys that you use to encrypt the keys you've stored on Github? Chicken? Egg?

Collapse
 
jeroen1205 profile image
Jeroen Jacobs

I suffer from the same dilemma all the time. I considered Hashicorp Vault as a credentials store, but you still need an access token to access the stored credentials, which means I need to store this token somewhere in my deployment tool (in my case, Ansilbe). Ansible has the ability to encrypt variables, but then I need to store that encryption key somewhere too. If you are automating all deployments (like I do), then you always need to store a secret somewhere. it's a never-ending cycle...

Collapse
 
jasongabler profile image
Jason Gabler

I suppose it's a matter of figuring out the most secure egg (or chicken, if you prefer), a lesser of all the evils. Meh.

Collapse
 
ianlivingstone profile image
Ian Livingstone

I've been working on Torus CLI for sharing secrets between humans and machines from development to production.

It integrates directly into your workflow, so you can model the way you store your secrets to the way you organize and deploy your code. All of the secrets are encrypted on the client using an elliptical curve keypair derived from your password.

Torus makes it easy to centralize all of your secrets and configuration, making it easy to share secrets in development, manage the configuration used directly in your CI/CD flow to ensure build secrets never touch disk, or in production by injecting secrets directly into a process using torus run via environment variables.

To give someone access, simply invite them to your org and add them to the appropriate teams. No decrypting files using gpg, dealing with binary merge conflicts, or educating users on how to keep secret keys or files safe.

When it comes time to rotate a secret, with one command it's out of rotation, you just need to deploy to bring everything up to date. Most importantly though, when someone leaves your company or changes teams, it's really easy to track down which secrets need to be rotated using the torus worklog command.

Collapse
 
pshchelo profile image
Pavlo Shchelokovskyy

Since the post and comments already touch on configuration mgmt solutions too, here is Ansible's answer to this problem - ansible-vault docs.ansible.com/ansible/2.4/vault...

Collapse
 
bpedro profile image
Bruno Pedro 💡

Thanks for sharing information about ansible-vault, Pavlo!

Collapse
 
dopitz profile image
Daniel O.

Some questions:
Where to store the secret key for the secrect storage?
How do you version and deploy the secrets?
How do you share the secrets in a team; per version and environment (dev, test, staging, prod)?

Environment variables are some kind of a "system wide global variable"
and not threat safe (see Laravel) in PHP. I would therefore not recommend it.

I came to the conclusion that a simple env.php is safe enough and works everywhere. This file is excluded via .gitignore. A developer can copy a versioned template of this file (example.env.php) and adapt it to his needs.

Collapse
 
mrcrandell profile image
Matt Crandell

For all PHP projects I've worked on, I've used github.com/vlucas/phpdotenv for all keys. I learned of it after working with Laravel projects.

Collapse
 
briankephart profile image
Brian Kephart

For anyone on Rails, the new encrypted credentials in version 5.2 are pretty nice. Before, I had to store sensitive information in my .env file locally as well as Heroku config. Now, I can just store it in an encrypted YAML file within the repo and keep only the encryption key in my environment.

Collapse
 
pastuh profile image
pastuh

I want to create chrome extension, which allows for everyone Create and Read files from MY repository. It's possible? And I can't hide API..
+Looks like all permissions allows not only create, but delete also..

Collapse
 
matchilling profile image
Mathias Schilling 💾

Hi Bruno, excellent post! I have used your article as an inspiration to write a brief tutorial on how to use AWS KMS and OpenSSL for protecting security-sensitive data in public GitHub/ Bitbucket repositories. Hope that is of any use for people who are looking to implement an encryption mechanism for their project.

Collapse
 
dangolant profile image
Daniel Golant

Any opinions on untracked, manually maintained env vars? Just for personal/small team projects, of course.

Collapse
 
washingtonsteven profile image
Steven Washington

This is what I usually do, with various packages (the vlucas package above for PHP, dotenv for node/JS) for managing the variables. I find working off a .env file is more applicable and cross platform, as various deploy tools can keep them secret and inject them for you and keeping them outside of a git repo.

At that point it's an issue of communicating those keys to the rest of the team/documenting them securely. I don't have a great solution for that. Password managers like LastPass or Dashlane could work, but might get awkward as you scale up team size?

Collapse
 
dangolant profile image
Daniel Golant

I've seen LastPass used for that sort of thing, and it's workable. I think a solution that fits a team that's grown past that is just a config script that is run on first setup that pulls all dev configs from a separate, secure store, which maybe pings a different company employee and then generates a one-time token for access, but that might be more or less security or configuration than some orgs need.

Collapse
 
andy profile image
Andy Zhao (he/him)

Hmm interesting. Thanks for sharing these different tools.

Collapse
 
bpedro profile image
Bruno Pedro 💡

Thanks for your kind comment, Andy!

Collapse
 
katakeynii profile image
Mohamed C. Gueye

Hi thank you a lot for sharing.What about storing API key not in project but in system env variables !?

Collapse
 
aelys profile image
Aelys

I create template files like "credentials.default.config" and put them on git. My app then read a "credentials.config" file that is not in the repository. This is the safest method I found.

Collapse
 
mellen profile image
Matt Ellen

Thanks for this. I was just looking for ways to deals with secrets and docker.