class Global::Backend::GcpSecretManager

Loads Global configuration from the Google Cloud Secret Manager cloud.google.com/secret-manager/docs

This backend requires the ‘google-cloud-secret_manager` gem, so make sure to add it to your Gemfile.

Available options:

For Rails:

Constants

GCP_SEPARATOR
PATH_SEPARATOR

Public Class Methods

new(options = {}) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 32
def initialize(options = {})
  @project_id = options.fetch(:project_id)
  require_gcp_gem
  init_prefix(options)
  init_client(options)
end

Public Instance Methods

load() click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 39
def load
  pages = load_all_parameters_from_gcsm

  configuration = {}
  pages.each do |page|
    configuration.deep_merge!(build_configuration_from_page(page))
  end

  configuration
end

Private Instance Methods

build_configuration_from_page(page) click to toggle source

builds a nested configuration hash from the array of parameters from Secret Manager

# File lib/global/backend/gcp_secret_manager.rb, line 104
def build_configuration_from_page(page)
  configuration = {}

  page.each do |parameter|
    key_name = get_gcp_key_name(parameter)
    next unless key_name.start_with?(@prefix)

    parameter_parts = key_name[@prefix.length..-1].split(PATH_SEPARATOR).map(&:to_sym)
    param_container = parameter_parts[0..-2].reduce(configuration) do |container, part|
      container[part] ||= {}
    end
    param_container[parameter_parts[-1]] = get_latest_key_value(key_name)
  end

  configuration
end
get_gcp_key_name(parameter) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 121
def get_gcp_key_name(parameter)
  parameter.name.split(GCP_SEPARATOR).last
end
get_latest_key_value(key_name) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 125
def get_latest_key_value(key_name)
  name = @gcsm.secret_version_path(
    project:        @project_id,
    secret:         key_name,
    secret_version: 'latest'
  )
  version = @gcsm.access_secret_version(name: name)
  version.payload.data
end
init_client(options) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 70
def init_client(options)
  if options.key?(:client)
    @gcsm = options[:client]
  else
    gcp_options = options.fetch(:gcp_options, {})
    @gcsm = Google::Cloud::SecretManager.secret_manager_service do |config|
      config.credentials = gcp_options[:credentials] if gcp_options[:credentials]
      config.timeout = gcp_options[:timeout] if gcp_options[:timeout]
    end
  end
end
init_prefix(options) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 58
def init_prefix(options)
  @prefix = if defined?(Rails)
              options.fetch(:prefix) do
                environment = Rails.env.to_s
                app_name = options.fetch(:app_name) { Rails.application.class.module_parent_name }
                "#{environment}-#{app_name}-"
              end
            else
              options.fetch(:prefix)
            end
end
load_all_parameters_from_gcsm() click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 82
def load_all_parameters_from_gcsm
  response = load_parameters_from_gcsm
  all_pages = [response]
  loop do
    break if response.next_page_token.empty?

    response = load_parameters_from_gcsm(response.next_page_token)
    all_pages << response
  end

  all_pages
end
load_parameters_from_gcsm(next_token = nil) click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 95
def load_parameters_from_gcsm(next_token = nil)
  @gcsm.list_secrets(
    parent: @gcsm.project_path(project: @project_id),
    page_size: 25_000,
    page_token: next_token
  )
end
require_gcp_gem() click to toggle source
# File lib/global/backend/gcp_secret_manager.rb, line 52
def require_gcp_gem
  require 'google/cloud/secret_manager'
rescue LoadError
  raise 'The `google-cloud-secret_manager` gem must be installed.'
end