Configuration and secrets management for Rails
Clone or download
Latest commit 95f6afe Oct 24, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin Initial commit Feb 23, 2018
lib Version 0.8.2 Oct 24, 2018
spec Obey template location order Oct 11, 2018
.gitignore Support multiple file sources for a single template Oct 10, 2018
.rspec Initial commit Feb 23, 2018
.rubocop.yml Initial commit Feb 23, 2018
.travis.yml Messing with travis config Jul 9, 2018 Version 0.8.2 Oct 24, 2018
Gemfile Initial commit Feb 23, 2018
Guardfile Initial commit Feb 23, 2018
LICENSE.txt Initial commit Feb 23, 2018
Procfile Initial commit Feb 23, 2018 Version 0.8.0 Oct 10, 2018
Rakefile Initial commit Feb 23, 2018
consult.gemspec Relax vault gem dependency Aug 27, 2018
docker-compose.yml Update consul/vault in docker-compose Oct 22, 2018


Generate configuration and secrets for Rails apps automatically from Consul & Vault.

Gem Version Build Status Maintainability


This gem is a spiritual sibling to Consul Template, but specifically intended for use in Ruby/Rails environments. It does not have the same features as Consul Template; it is intended for simpler scenarios. Most importantly, leases and configuration changes are not watched to automatically re-render. Consult is intended for more static or medium-to-long lived application configuration.

We use Consul Template for server level configuration, but application level configuration is more tricky. It is difficult to solve the problem of fetching configuration and secrets in a consistent way in development, staging, and production. For example, we wanted to avoid having Consul Template used in production, but some other custom solution in development.

With Consult the process is the same in all environments.

This gem is considered beta. At Veracross, we are just beginning to use it in staging environments.


Add this line to your application's Gemfile:

gem 'consult'

And then execute:

$ bundle

Or install it yourself as:

$ gem install consult


Using Consult requires a configuration YAML file and a series of template files. The configuration file serves as a manifest of templates and their settings, along with optional connection settings to Vault and Consul.

Pre-existing copies of files generated by Consult (such as secrets.yml, database.yml, etc) should be removed from your app's source control and added to your .gitignore. Only keep your templates in source control, not the generated files!

If this gem is included in a Rails, the templates will render on Rails boot. Configuration or credential changes can be picked up by restarting your app.


# Optional; Consult will render this specific environment, if set
# Defaults to ENV['RAILS_ENV'] or Rails.env if Rails is present
env: test

# "shared" is the base configuration used for all environments by default
# note: you do NOT need to use yaml merge syntax to have shared configuration included for specific environments
  # Optional
    # Prefers `CONSUL_HTTP_ADDR` environment variable
    # Prefers `CONSUL_HTTP_TOKEN` environment variable, or a ~/.consul-token file.
    # Setting a token here is not best practice because consul tokens should have a relatively short TTL
    # and be read from the environment, but this is convenient for testing.
    token: 5d3f1c66-d405-4ad1-b634-ea30be4fb539

  # Optional
    # Prefers `VAULT_ADDR` environment variable
    # Prefers `VAULT_TOKEN` environment variable, or a ~/.vault-token file
    # Setting a token here is not best practice because vault tokens should have a relatively short TTL
    # and be read from the environment, but this is convenient for testing.
    token: 8fcd5aed-3eb9-412d-8923-1397af7aede2

  # Enumerate the templates.
      # Relative paths are assumed to be in #{Rails.root}.
      # Path to the template
      path: config/templates/database.yml
      # Destination for the rendered template
      dest: config/database.yml
      # If the file is less than this old, do not re-render
      ttl: 3600 # seconds

# environment specific configuration
# NOTE: environment keys will be deep merged with the "shared" configuration
      path: config/templates/secrets.yml
      dest: config/secrets.yml

    # You can concatenate multiple files together
        - config/templates/one.yml
        - config/templates/two.yml
      dest: config/my_config.yml

    # Templates can come from Consul
        - some/consul/key
        - another/consul/key
      dest: config/your_config.txt


Templates files are processed with ERB. As such, they can do anything ERB can do. Consult also provides a few helper functions.

Note that under the hood, Consult is using Diplomat and the Vault Gem. Consul objects are therefore Diplomat objects, and likewise Vault objects are Vault Gem objects. See their API docs for more information. Diplomat generally returns structs with title cased properties.

Consul Functions

service(name) - Fetch the nodes for the specified service.

<% service("redis").each do |node| %>
host: <%= node.Address %>
port: <%= node.ServicePort %>
<% end %>


host: redis1.local
port: 6379

query(name_or_id, options: nil) - Execute the specified prepared Query by name or ID

<% query('pg-production').tap do |result| %>
  service: <%= result.Service %>
  <% result.Nodes.each do |node| %>
    address: <%= node['Node']['Address']
  <% end %>
<% end %>

query_nodes(name_or_id, options: nil) - Return only the nodes from a prepared query

<% query_nodes('pg-production').each do |node| %>
<%= node['Node'] %>:
  host: <%= node['Address'] %>
  datacenter: <%= node['Datacenter'] %>
<% end %>
  datacenter: us-east-1
  datacenter: us-east-2

key(key, options: nil, not_found: :reject, found: :return) - Return value of the given key

'<% key('apps/infrastructure/node/dns') %>':
<<: *common
  host: <%= key('apps/infrastructure/node/dns') %>
  port: 1433
<<: *common
  host: db1
  port: 1433

Vault Functions

secret(path) - Fetch a secret at the given path.

# Vault KV v2
username: <%= secret('secret/data/credentials').data.dig(:data, :username) %>

# Vault KV v1
username: <%= secret('secret/credentials').data[:username] %>



secrets(path) - List all secrets at the given path

<% secrets('secret').each do |path| %>
  <%= path %>
<% end %>



Utility Functions

timestamp - Renders the current utc timestamp.

<%= timestamp %>


2018-02-23 14:20:29 UTC

indent(string, level, separator = '\n') - Indents a multi-line string by level

  multi_line: |
<%= indent secret('secret/keys/multi_line).data[:value], 4 %>


  multi_line: |

with(whatever) - takes whatever and yields it back. Equivalent to tap, but provided as a bridge from [Consul Template]/Go template conventions.

<% with secret "secrets/credentials" do |s| %>
username: <%=[:username] %>
password: <%=[:password] %>
<% end %>

More Full Examples

Render multiple servers into a database.yml file, keyed by their name.

# database.yml
<% service("postgres").each do |node| %>
'<%= node.Node %>':
  host: <%= node.Address %>
  port: <%= node.ServicePort %>
  <%- with secret "secret/base/sql-server/#{node.Node}/web" do |s| -%>
  # Credential lease good until <%= (timestamp + s.lease_duration).to_s %>
  username: <%=[:username] %>
  password: <%=[:password] %>
  <% end -%>
<% end %>

Yields something like

# database.yml
  port: 5432
  # Credential lease good until 2018-02-24 16:08:29 UTC
  username: foo
  password: bar
  port: 5432
  # Credential lease good until 2018-02-24 16:08:29 UTC
  username: baz
  password: qux


# secrets.yml
  rollbar_token: <%= secret('secrets/third_party').data[:rollbar] %>
  scout_token: <%= secret('secrets/third_party').data[:scout] %>

  secret_key_base: abcd1234....

  secret_key_base: <%= secret('secret/apps/myapp').data[:secret_key_base] %>

Then reference secrets in your app with Rails.application.secrets.

# config/intiializers/rollbar.rb
Rollbar.configure do |config|
  config.access_token = Rails.application.secrets.rollbar_token


After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment. See below for testing instructions.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to


Testing is easiest by running Consul and Vault in Docker. Just boot up their minimal containers:

$ docker-compose up

Then run bundle exec rspec, or bundle exec guard.


Bug reports and pull requests are welcome on GitHub at


The gem is available as open source under the terms of the MIT License.