class Hako::EnvProviders::Vault

Constants

REQUIRED_PARAMS

Public Class Methods

new(_root_path, options) click to toggle source

@param [Pathname] root_path @param [Hash<String, Object>] options

# File lib/hako/env_providers/vault.rb, line 15
def initialize(_root_path, options)
  REQUIRED_PARAMS.each do |k|
    unless options[k]
      validation_error!("#{k} must be set")
    end
  end
  unless ENV['VAULT_TOKEN']
    validation_error!('Environment variable VAULT_TOKEN must be set')
  end

  uri = URI.parse(options['addr'])
  @http = Net::HTTP.new(uri.host, uri.port)
  if uri.scheme == 'https'
    @http.use_ssl = true
  end
  @directory = options['directory']
end

Public Instance Methods

ask(variables) click to toggle source

@param [Array<String>] variables @return [Hash<String, String>]

# File lib/hako/env_providers/vault.rb, line 35
def ask(variables)
  env = {}
  @http.start do
    variables.each do |key|
      res = get_with_retry("/v1/secret/#{@directory}/#{key}")
      case res.code
      when '200'
        env[key] = JSON.parse(res.body)['data']['value']
      when '404'
        nil
      else
        raise Error.new("Vault HTTP Error: #{res.code}: #{res.body}")
      end
    end
  end
  env
end
ask_keys(variables) click to toggle source

@param [Array<String>] variables @return [Array<String>]

# File lib/hako/env_providers/vault.rb, line 60
def ask_keys(variables)
  keys = []
  @http.start do
    parent_directories_for(variables).each do |parent_dir|
      res = get_with_retry("/v1/secret/#{@directory}/#{parent_dir}?list=true")
      case res.code
      when '200'
        keys += JSON.parse(res.body)['data']['keys'].map { |key| "#{parent_dir}#{key}" }
      when '404'
        # Ignore
      else
        raise Error.new("Vault HTTP Error: #{res.code}: #{res.body}")
      end
    end
  end
  keys.select { |key| variables.include?(key) }
end
can_ask_keys?() click to toggle source

@return [Boolean]

# File lib/hako/env_providers/vault.rb, line 54
def can_ask_keys?
  true
end

Private Instance Methods

get_with_retry(path) click to toggle source

@param [String] path @return [Net::HTTPResponse]

# File lib/hako/env_providers/vault.rb, line 92
def get_with_retry(path)
  last_error = nil
  10.times do |i|
    req = Net::HTTP::Get.new(path)
    req['X-Vault-Token'] = ENV['VAULT_TOKEN']
    res = @http.request(req)
    code = res.code.to_i
    if retryable_http_code?(code)
      Hako.logger.warn("Vault HTTP Error: #{res.code}: #{res.body}")
      last_error = res
      interval = 1.5**i
      Hako.logger.warn("Retrying after #{interval} seconds")
      sleep(interval)
    else
      return res
    end
  end
  raise Error.new("Vault HTTP Error: #{last_error.code}: #{last_error.body}")
end
parent_directories_for(variables) click to toggle source

@param [Array<String>] variables @return [Array<String>]

# File lib/hako/env_providers/vault.rb, line 82
def parent_directories_for(variables)
  # XXX: URI module cannot join relative URIs
  base_uri = URI.parse('https://dummy/')
  variables.map do |variable|
    (base_uri + variable + '.').request_uri.sub(%r{\A/}, '')
  end.uniq
end
retryable_http_code?(code) click to toggle source
# File lib/hako/env_providers/vault.rb, line 112
def retryable_http_code?(code)
  code == 307 || (code >= 500 && code < 600)
end