I’m now versioning my app secrets in Git, here is why you should do the same.
By: Andréas Hanss
Tags: JavaScript, Software, Cloud, Encryption, AWS

Back on Monday, the company received several emails, mentioning that the billing as ignited and with the maximum restrictions they reached 15 000€ in just 2 days. That’s not so cool for a small commit of fail like this… The thing is that it’s happening to many people every year.

You have to know that those keys have a specific pattern and there is a bunch of bots that are crawling the web searching for that pattern.

What happened is that someone had populated several of the biggest CPU optimized VM in order to crypto mine some Bitcoin (BTC).

The moral of this story is: Never commit any sensitive data anywhere to prevent any accidental leak, even on the small repositories you might think that they will never become public.

For that, most cloud provider services allow managing secrets in a secure way, that will be injected on runtime directly in cloud functions or the VM through Environment variables. This is a really cool thing and starting that day, I was applying that anywhere, even on my own private repository, just in case…

…Until last week, where I wanted to add to my already not so small collection of secret a serialized version of a Firebase Service account, which is a JSON file with amongst others a full RSA string key.

There are some limitations on some provider about secrets management

Despite the fact that managing complexes secrets is something hard using environment variables (e.g: RSA keys pair, JSON config, …) there are some other limitations…

And on Zeit Now, which is kind of a wrapper around AWS, there is an upstream limit in terms of size of secrets…

This means for those who are base64 'ing complexes' secrets such as Firebase/ Google credentials and service account, you will probably exceed the limit. This happened to me and to many others.

All of this leads me to another technique: Encryption.

From 99 secrets to 1 secret with a versioned encrypted JSON configuration

Instead of defining various environments variables as secrets to store my private configuration and hit the limits. I’m using symmetric encryption to store one complete JSON file that contains my secured configuration.

The only thing that remains in the cloud secrets storage is the encryption key and —potentially— the initiation vector (IV) that is used to cipher this configuration object.

This practice as some benefits:

All the configuration stands in one place.

You can easily store JSON structures and namespace your config parameters properly.

It is safe.

It’s IDE and developer-friendly, with statics typings and auto-completion.

Generally speaking, if you’re not a rookie and apply the basics of security, there isn’t many chances that someone successfully breaks through your security and steals your code repository without having you get notified.

But even if it happens here, using the following strategy you’ll be safe because, like your database passwords, your whole configuration is encrypted.

That way you have far enough time to invalidate and generate new access keys for any of your services and secure your repository again.

But wait… What is symmetric encryption?

A quick reminder about symmetric encryption

Symmetric Encryption in a nutshell — Wikipedia

Symmetric encryption is the action of encoding a text (here, a stringified JSON) using a randomly generated key. Using the same key, the program is able to decrypt this chunk of data later and restore it.

In addition to the key, each time we encrypt the stringified configuration object, we use a random chunk of data called an Initialization Vector (IV). This prevents having the same encryption results when ciphering several times the same document. Which increases security.

All of this is done using a technique called Cipher Block Chaining (CBC) if you want to read more about it feel free to Google about it or Wikipedia.

Good news, it’s pretty easy to use a CBC cipher in NodeJS. It’s supported out-of-the-box using the crypto module on top OpenSSL.

Using Cipher IV CBC to encrypt a JSON configuration for your cloud projet

The following example is split into 2 parts:

First: encryption. We will encrypt on the developer computer the desired JSON configuration object. We could have done this on some websites such as this one but I respectfully disagree with that practice. You should never take any risks and expose your configuration on an external website and/or letting someone else generate your encryption key. Otherwise, it’s useless to encrypt something. Once we have the encrypted string, we just add it to our repository and commit it with our source code. Second: decryption. We will decrypt the configuration when the code is bootstrapping using our encryption key injected by the secrets provider in our environment variables and make it available in our application.

Ready? Let’s code!