jlevy

jlevy

Storing config secrets securely

I’m getting ready to deploy my first Elixir app, and it manages very sensitive data. I plan to use Distillery for releases, and I’m clear on how it manages configuration. What I’m not sure of is the best way to handle secrets like API keys and the Ecto Repo DB credentials. Here are a few approaches I’ve considered:

  1. Use config.exs or prod.exs: This isn’t compatible with Distillery because the values would be evaluated at compile time. There is also the risk that these types of files might be checked into a Git repository accidentally.

  2. Use environment variables as discussed on the plataformatec blog and promoted by the 12-Factor App: This approach is not universally embraced. The overall consensus of this discussion seems to be that environment variables were never intended to be private, and they may be inadvertently exposed. Many argue that files are inherently more secure because access to them can be controlled and reasoned about through permissions, which is lacking for the environment.

  3. Store the configuration in a file located away from the code, such as in /etc. This seemed appealing, until I released that I wouldn’t be able to lock down the permissions very much. The user that the release is running as will need read access, and isn’t that the riskiest user to have access?

  4. Encrypt the secrets using something like AWS KMS. On app startup, send an HTTP request to decrypt them and store them only in memory. Yes, we still need to store the AWS credentials somehow, but at least we can restrict access by IP, and all KMS requests are logged so we can configure some type of alert every time a decryption call is made. But is this even possible? Would I then set the env manually using Application.put_env? Would I need a separate app to handle configuration decryption and loading before the target app is executing? Do I need to be worried about this warning in the docs? Do not use the functions in this module for directly accessing or modifying the environment of other applications (as it may lead to inconsistent data in the application environment).

  5. I thought maybe I could use the transforms feature is Conform to handle decryption, but it looks like the output of this tool is an erlang sys.config file that gets written to disk. That doesn’t solve the problem.

I’m sure this must be a solved problem. How are others dealing with this? Am I just being unreasonably paranoid?

Most Liked

Qqwy

Qqwy

TypeCheck Core Team

One of the things that I know of certain companies that require high security do, is to store the configuration settings in an encrypted file (stored in a logical place, away from the code somewhere, i.e. using your approach number 3.). The program will then prompt for the proper passphrase to decrypt this file when it is started.

This means that the only way for an attacker to read the secret configuration information, is to either be able to read your keystrokes while you restart the server, or read (and basically disassemble) part of the RAM that your running program is using.


I’ve also heard about servers deployed this way that ran fine for years, and then when they finally had to restart, they asked for a password that nobody remembered anymore… :sweat_smile:

mkunikow

mkunikow

Docker Online Meetup: What’s new in Docker 1.13

KallDrexx

KallDrexx

While this isn’t Elixir specific, we have a two prong approach for handling our secret config for our highly available and global Asp.Net systems, utilizing both configuration in Environment Variables and in a configuration environment.

Originally we were doing all configuration via environment variables. This became tedious and difficult to properly maintain as we scaled the number of configuration settings we had to maintain as well as scaling our systems to different geographic data centers, (not to mention staging systems that can be swapped between prod and staging). A lot of configuration stayed the same between each region but some things didn’t and keeping track of that was difficult.

So how we handled it was by loading configuration twice. First past is reading the deployed configuration file (which really only has defaults) then overriding them with environment variables. We then pull the connection string out and then repeat the process with the database (so config file overwritten by database overwritten by environment variables).

Each server can specify in the environment variables a configuration profile (for example it’s region), which adds an extra layer of optional overrides. This allows us to do things like keep our east coast servers queuing up data in our east coast queues and keep latencies as a whole down.

This allows us to keep the environment variable maintenance down (only requiring database connection string and prod/staging specific settings) while making it very easy to query to see what settings will be applicable to a specific server. Not only that, since our databases are backed up in a way that allow us to restore to any point in time if something gets fubar we have a way to restore them back.

benperiton

benperiton

As part of another project I’ve been looking at ways to securely store secrets, and one of the things that stood out when trying Vault was the ways that apps could be used with it.

So for the case of getting credentials for an app, using the Cubbyhole secret backend seems like a good way to mitigate unwanted access to tokens.

The basic idea is;

  • Enable Cubbyhole secret backend. (Vault enables this by default)
  • Create temporary token with use count of 2. (The use count specifies number of times the specific token can be used)
  • Create permanent token.
  • Store permanent token in temporary token’s cubbyhole.
  • Pass temporary token to container application using environment variable.
  • Application reads permanent token from cubbyhole using temporary token.

Even if temporary token is read by malicious user later, there is no use for it since the use count for temporary token would have expired. Out of the specified initial use count of 2 for temporary token, first count is used when writing the permanent token and the second count is used when reading the permanent token.

I’m not sure how easy it would be to integrate, I’m thinking some sort of upstart script that gets the temporary token then passes it to the elixir app on startup, then internally the app does the rest - doing something like Preparing for Production - #2 by sasajuric

Some more info on response wrapping using Cubbyholes:

This post has an example of that, as well as the DB secret backend for authenticating DB users:

ibgib

ibgib

At the end of Paul Schoenfelder’s (@bitwalker) excellent deployment talk on Distillery, someone asks this very question about managing secrets. His response is brief and I won’t paraphrase! :speak_no_evil:

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement