View Source Usage tutorial

This is a 5 minutes SecretVault tutorial that shows how to install and configure SecretVault, and then create, delete, edit, and access secrets in runtime.

Install

Just add it into your dependencies like

defp deps do
  [
    {:secret_vault, "~> 1.0"}
  ]
end

Create priv dir

Just create a priv directory in the root of your project

Configure

Configuration is straightforward. Minimal configuration would look like this:

import Config

config :my_app, :secret_vault,
  default: [password: System.fetch_env!("SECRET_VAULT_PASSWORD")]

# Here `default` is a name of a default prefix. Prefixes work like namespaces for secrets.

You can provide options other than password. To see a full list of those check out the SecretVault.Config.new/2 documentation.

Note

Each MIX_ENV will have it's own separate vault, so don't use prefixes to separate envs.

Create secrets

To create a secret during development, you can use one of many secret creating tasks available. But do not forget to provide the enviroment variable with the password which we specified above.

For example,

$ export SECRET_VAULT_PASSWORD="password" # Don't forget to change the password value
$ mix scr.insert dev database_password "My Super Secret Password"

Or, to be able to write a password in your favourite editor, use

$ mix scr.create dev database_password

Here dev defines the MIX_ENV for which you'd like to create a secret. And database_password is a name of the secret. These exact commands will create a secret in priv/dev/default/database_password.vault_secret. Each secret is written onto it's own file in vault directory in priv. This plays nice with version control systems and simplifies the user interface.

Note

Each secret is written into it's own file with .vault_secret extension. Therefore, secrets' names must be suitable file names.

Manipulate secrets

To edit already created secrets, one can use mix scr.insert and mix scr.edit commands. To delete, rename or copy secrets, one can use regular coreutils like mv, cp, rm, since each secret is placed under the corresponding directory in priv. Usually the path is priv/$MIX_ENV/$PREFIX/${SECRET_NAME}.vault_secret.

For example, to delete secret which was created in previous step, one could write:

$ rm priv/dev/default/database_password.vault_secret

Or to rename a secret:

$ cd priv/dev/default/
$ mv database_password.vault_secret db_password.vault_secret

Access secrets

To access and use secrets from Elixir application, one first need to retrieve the vault configuration. Then, it is recommended to place the secrets into some runtime storage (like persistent_term, for example).

So, regular workflow would look like

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    ...
    {:ok, config} = SecretVault.Config.fetch_from_current_env(:my_app)
    SecretVault.Storage.to_persistent_term(config)
  end
end

This will create config from configuration of your application and put all decrypted passwords in the persistent_term. See SecretVault.Config and SecretVault.Storage for more options.

If you want to have you options in application env you can specify this in config.exs

# in config/config.exs
import Config

config :my_app, :secret_vault,
  default: [password: System.fetch_env!("SECRET_VAULT_PASSWORD")]

# in application.ex start function
{:ok, config} = SecretVault.Config.fetch_from_current_env(:my_app)
SecretVault.Storage.to_application_env(config)

Runtime configuration

It is a common practice to configure application in configuration scripts like config/config.exs, config/dev.exs and config/runtime.exs. And there are two things a developer must keep in mind while working with them

First of all, you must not use compile time configuration scritps (basically everything except runtime.exs) for setting values from secrets, since these values will appear in app.src file in your _build or release ebin directory. Usually, this is not something you can tolerate

Second, runtime.exs config will be called during initialization of your project and the enviroment of the project will be inherited from the enviroment which was during project compilation. This means, that for release created with MIX_ENV=dev mix release and called with MIX_ENV=prod myapp start, secrets (and all other configuration) will be fetched from dev enviroment.

So, to configure secrets in runtime, you can write something like:

# in config/runtime.exs
import Config
import SecretVault, only: [runtime_secret!: 2]

config :playground, MyApp.Repo,
  password: runtime_secret!(:playground, "database_password")

Release

There is no special behaviour for releases. Just mix release and use. Don't forget to add mix scr.audit task in your CI to enforce quality of passwords.