Skip to content

Commit

Permalink
Set secret_key_base early enough for rails processes
Browse files Browse the repository at this point in the history
We don't use secret_key_base like vanilla rails. We implemented secrets through
MiqPassword before any of this existed in rails.  Our only things currently going
through rails secrets perhaps is the provider vcr cassette information.

Rails 7.1 asserts secret_key_base is now set and set during rails boot fairly early.

So, now, we can't only set this for puma based workers, but all rails processes.
We also, must move this logic to be done earlier during boot.  It was found that
after eager load allows us to leverage autoload and access the database, both
are required in order to fetch the secrets from the database.

Move over the logic for rails console so it can use a dummy secret key base.

Move the tests to a vmdb/initializer test.

Co-Authored-By: Jason Frey <fryguy9@gmail.com>
  • Loading branch information
jrafanie and Fryguy committed Feb 24, 2025
1 parent 99489ca commit 839fc1a
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 57 deletions.
17 changes: 0 additions & 17 deletions app/models/mixins/miq_web_server_worker_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,8 @@ def binding_address
BINDING_ADDRESS
end

def preload_for_console
configure_secret_token(SecureRandom.hex(64))
end

def preload_for_worker_role
raise "Expected database to be seeded via `rake db:seed`." unless EvmDatabase.seeded_primordially?

configure_secret_token
end

def configure_secret_token(token = MiqDatabase.first.session_secret_token)
return if Rails.application.config.secret_key_base

Rails.application.config.secret_key_base = token

# To set a secret token after the Rails.application is initialized,
# we need to reset the secrets since they are cached:
# https://github.com/rails/rails/blob/7-0-stable/railties/lib/rails/application.rb#L392-L404
Rails.application.secrets = nil if Rails.version < "7.1"
end

def rails_server
Expand Down
5 changes: 5 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ class Application < Rails::Application
end
end

# Run after code is eager loaded so we can autoload MiqDatabase and ApplicationRecord
initializer :init_secret_token, :after => :eager_load! do
Vmdb::Initializer.init_secret_token
end

config.after_initialize do
Vmdb::Initializer.init
ActiveRecord::Base.connection_pool.release_connection
Expand Down
13 changes: 10 additions & 3 deletions lib/vmdb/initializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ def self.init
MiqServer.my_server.starting_server_record
MiqServer.my_server.update(:status => "started")
end
end

def self.init_secret_token
return if Rails.application.config.secret_key_base

# Rails console needs session store configured
if defined?(Rails::Console)
MiqUiWorker.preload_for_console
token = if ActiveRecord::Base.connectable? && MiqDatabase.table_exists? && MiqDatabase.any?
MiqDatabase.first.session_secret_token
else
SecureRandom.hex(64)
end

Rails.application.config.secret_key_base = token
end

private_class_method def self.log_db_connectable
Expand Down
41 changes: 41 additions & 0 deletions spec/lib/vmdb/initializer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
RSpec.describe Vmdb::Initializer do
describe ".init_secret_token" do
before do
@token = Rails.application.secret_key_base
end

after do
Rails.application.config.secret_key_base = @token
Rails.application.secrets = nil
end

it "defaults to MiqDatabase session_secret_token" do
MiqDatabase.seed
Rails.application.config.secret_key_base = nil
Rails.application.secrets = nil

described_class.init_secret_token
expect(Rails.application.secret_key_base).to eq(MiqDatabase.first.session_secret_token)
expect(Rails.application.config.secret_key_base).to eq(MiqDatabase.first.session_secret_token)
end

it "uses random hex when MiqDatabase isn't seeded" do
Rails.application.config.secret_key_base = nil
Rails.application.secrets = nil

described_class.init_secret_token
expect(Rails.application.secret_key_base).to match(/^\h{128}$/)
expect(Rails.application.config.secret_key_base).to match(/^\h{128}$/)
end

it "does not reset secrets when token already configured" do
existing_value = SecureRandom.hex(64)
Rails.application.config.secret_key_base = existing_value
Rails.application.secrets = nil

described_class.init_secret_token
expect(Rails.application.secret_key_base).to eq(existing_value)
expect(Rails.application.config.secret_key_base).to eq(existing_value)
end
end
end
37 changes: 0 additions & 37 deletions spec/models/mixins/miq_web_server_worker_mixin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,6 @@
end
end

before do
@token = Rails.application.secret_key_base
MiqDatabase.seed
end

after do
Rails.application.config.secret_key_base = @token
Rails.application.secrets = nil if Rails.version < "7.1"
end

it ".configure_secret_token defaults to MiqDatabase session_secret_token" do
Rails.application.config.secret_key_base = nil

test_class.configure_secret_token
expect(Rails.application.secret_key_base).to eq(MiqDatabase.first.session_secret_token)
expect(Rails.application.config.secret_key_base).to eq(MiqDatabase.first.session_secret_token)
end

it ".configure_secret_token accepts an input token" do
Rails.application.config.secret_key_base = nil

token = SecureRandom.hex(64)
test_class.configure_secret_token(token)
expect(Rails.application.secret_key_base).to eq(token)
expect(Rails.application.config.secret_key_base).to eq(token)
end

it ".configure_secret_token does not reset secrets when token already configured" do
existing_value = SecureRandom.hex(64)
Rails.application.config.secret_key_base = existing_value
Rails.application.secrets = nil if Rails.version < "7.1"

test_class.configure_secret_token
expect(Rails.application.secret_key_base).to eq(existing_value)
expect(Rails.application.config.secret_key_base).to eq(existing_value)
end

it "#rails_server_options" do
w = FactoryBot.create(:miq_ui_worker, :uri => "http://127.0.0.1:3000")
expect(w.rails_server_options).to include(
Expand Down

0 comments on commit 839fc1a

Please sign in to comment.