Skip to content

Commit

Permalink
Add read-only configuration
Browse files Browse the repository at this point in the history
- When read-only mode is enabled via rails config, controller endpoints that are explicitly enrolled into a `write_protected` list return a HTTP 405 Method Not Allowed when invoked, also throwing Conjur error code: `CONJ00153E`
- Implemented using module prepending
  • Loading branch information
codihuston committed Aug 15, 2023
1 parent 0c6c4b2 commit 380bb0a
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class UnprocessableEntity < RuntimeError
rescue_from GatewayTimeout, with: :gateway_timeout
rescue_from BadGateway, with: :bad_gateway
rescue_from Exceptions::NotImplemented, with: :not_implemented
rescue_from Errors::Conjur::ReadOnly::ActionNotPermitted, with: :method_not_allowed
rescue_from Sequel::ValidationFailed, with: :validation_failed
rescue_from Sequel::NoMatchingRow, with: :no_matching_row
rescue_from Sequel::ForeignKeyConstraintViolation, with: :foreign_key_constraint_violation
Expand Down
15 changes: 15 additions & 0 deletions app/controllers/concerns/prepend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module ReadOnlyPrepender
# Given a list of method symbols, preempt calls to them using a proxy that
# raises an error if read_only is enabled.
def write_protected(*method_names)
method_names.each do |m|
proxy = Module.new do
define_method(m) do |*args|
raise ::Errors::Conjur::ReadOnly::ActionNotPermitted unless !Rails.configuration.read_only
super *args
end
end
self.prepend proxy
end
end
end
3 changes: 3 additions & 0 deletions app/controllers/policies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
class PoliciesController < RestController
include FindResource
include AuthorizeResource
extend ReadOnlyPrepender

before_action :current_user
before_action :find_or_create_root_policy
write_protected :put, :patch, :post
after_action :publish_event, if: -> { response.successful? }

rescue_from Sequel::UniqueConstraintViolation, with: :concurrent_load
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/secrets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
class SecretsController < RestController
include FindResource
include AuthorizeResource
extend ReadOnlyPrepender

before_action :current_user
write_protected :create, :expire

def create
authorize(:update)
Expand Down
7 changes: 7 additions & 0 deletions app/domain/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ module Conjur
msg: "Resource '{0-resource}' requested by role '{1-role}' not found",
code: "CONJ00123E"
)

module ReadOnly
ActionNotPermitted = ::Util::TrackableErrorClass.new(
msg: "This action is not permitted when the server is in read-only mode",
code: "CONJ00153E"
)
end
end

module Authorization
Expand Down
1 change: 1 addition & 0 deletions config/environments/appliance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
config.middleware.use(Rack::RememberUuid)
config.audit_socket = '/run/conjur/audit.socket'
config.audit_database ||= 'postgres://:5433/audit'
config.read_only = false
end
15 changes: 15 additions & 0 deletions config/initializers/read_only_mode.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

Rails.application.configure do
# Determines whether or not writable API endpoints are enabled.
#
# The `read_only` arguement is a boolean. By default, `read_only` is "Off".
# This means that any of the writable API endpoints will function as intended.
#
# A writable API endpoint is one whose controller method is decorated with the
# `@read_safe` decorator. When `read_only` is "On", such endpoints will return
# an HTTP 405 Method Not Allowed response code.
#
config.read_only = false
end

0 comments on commit 380bb0a

Please sign in to comment.