Стремясь лучше защитить наши производственные данные, в прошлом году мы решили настроить консоль производственной консоли Readonly. Это позволяет разработчикам такать по производственным данным, не беспокоясь о том, что они могут случайно изменить то, что не должны. В этом посте я разбим именно то, что мы сделали, чтобы сделать это для нашего приложения Ruby on Rails.
Прежде чем погрузиться в специфику для каждой базы данных, я хочу сначала упомянуть, что мы используем совершенно отдельный сервер для консоли. Использование отдельного сервера позволяет нам настраивать настройки приложения для достижения доступа к чтениям. Чтобы развернуть эти изменения, мы используем Ansible Анкет Когда Ansible запускает развертывание, он ищет тег для консоли, чтобы узнать, какие настройки и конфигурации должны быть развернуты в этом конкретном поле.
Первое, что мы сделали, — это настроить пользователя с Readonly Access в MySQL. Затем, чтобы сделать наше приложение Readonly для MySQL, все, что нам просто нужно было сделать, это поместить учетные данные пользователя READONLY в нашем Database.yml
Файл в нашем консольном сервере.
production: adapter: mysql2 encoding: utf8 reconnect: true pool: 16 database: "prod_db" username: "readonly" password: "you_wish" host: "127.0.0.1" strict: false
Теперь Каждый раз, когда кто -то открывает консоль рельсов на нашем консольном сервере, он автоматически использует учетные данные для чтения из конфигурации.
Тем не менее, есть еще времена, когда мы хотим иметь возможность позволить разработчикам редактировать данные через консоль. Чтобы сделать это, мы установили сценарий Bash, который используется для открытия консоли рельсов. В этом сценарии Bash мы решили использовать менее известную функцию, которая предлагает Rails, Database_url
Анкет Если вы установите Database_url
Переменная в вашей среде, Rails будет использовать его для подключения к вашей базе данных, а не для чтения из вашего Database.yml
файл. Это позволяет нам переопределить наши конфигурации базы данных, когда нам нужно. Мы установили его в нашем сценарии Bash, как:
#!/bin/bash cd /application_path if [ "$1" = 'write' ]; then export DATABASE_URL="mysql2://write_username:write_password@host/db_name" fi RAILS_ENV=production /usr/local/bin/bundler exec rails console
Теперь, если разработчик должен редактировать данные, он может просто открыть консоль записи, используя команду Консоль записи
Анкет
Чтобы обработать настройку Redis как Readonly, мы решили переопределить нашего клиента Redis, чтобы явно блокировать любые команды записи. Поскольку у нас есть приложение Ruby on Rails, мы используем Redis-rb драгоценный камень, чтобы поговорить с Redis. Чтобы заблокировать команды записи, мы сначала собрали все команды, которые писали, на основе вызова Команда
Метод на нашем клиенте Redis. Для справки, Rails.cache.data
просто даст вам ваш клиент Redis.
dev> Rails.cache.data => #
Команда
Метод вернет массив всех команд, на которые ваш экземпляр REDIS ответит вместе с некоторой дополнительной информацией о каждой команде.
dev> Rails.cache.data.command.first(3) => [["expireat", 3, ["write", "fast"], 1, 1, 1], ["setnx", 3, ["write", "denyoom", "fast"], 1, 1, 1], ["getrange", 4, ["readonly"], 1, 1, 1]]
Чтобы отфильтровать только команды записи, мы просто проверили для значения «записать» в списке атрибутов команды.
WRITE_COMMANDS = Rails.cache.data.command.map { |a| a[0] if a[2].include?('write') }.compact.to_set
Как только у нас появился список команд записи, мы отвергли процесс
Метод В нашем жемчужине, чтобы выдвинуть ошибку, если был вызван какой -либо из этих методов.
def process(commands) if commands.flatten.any? { |c| WRITE_COMMANDS.include?(c.to_s) } raise NotImplementedError, "REDIS_ACCESS_MODE is set to 'readonly', disallowing writes" end # additional method logic end
Эти две части позволяют нам блокировать команды Redis записи. Но все еще остается вопрос, как мы можем блокировать эти команды записи только в нашем консольном поле? Еще раз, мы обратились к нашим переменным окружающей среде и нашему сценарию консоли. В нашем консольном скрипте мы устанавливаем переменные среды на основе того, была ли консоль в чтении по умолчанию или если это была консоль записи.
#!/bin/bash cd /application_path if [ "$1" = 'write' ]; then export DATABASE_URL="mysql2://write_username:write_password@host/db_name" export REDIS_ACCESS_MODE="" else export REDIS_ACCESS_MODE="readonly" fi RAILS_ENV=production /usr/local/bin/bundler exec rails console
Тогда в нашем Redis.rb
Файл инициализатора В нашем приложении мы обезьяны исправлены метод процесса, чтобы вернуть ошибку, если команда записи была вызвана в режиме Readonly Access.
if ENV['REDIS_ACCESS_MODE'] == 'readonly' class Redis class Client WRITE_COMMANDS = ::Rails.cache.data.command.map { |a| a[0] if a[2].include?('write') }.compact.to_set.freeze def process(commands) if commands.flatten.any? { |c| WRITE_COMMANDS.include?(c.to_s) } raise NotImplementedError, "REDIS_ACCESS_MODE is set to 'readonly', disallowing writes" end # additional method logic end end end end
Бум! Консольная коробка была теперь читалась для MySQL и для Redis по умолчанию. Остался только один кусок головоломки, Elasticsearch.
Elasticsearch находится на краеугольном камне нашего приложения, поэтому нам нужно было, чтобы это также было читаемым. Чтобы поговорить с Elasticsearch, мы используем Elasticsearch-ruby жемчужина Во многом так же, как мы делали Redis, мы нашли основной метод, используемый для выполнения внешних запросов в Elasticsearch, exector_resquest
и исправил его так, чтобы это выдвинуло ошибку всякий раз, когда был выполнен метод записи. Поскольку мы разговариваем с Elasticsearch, используя HTTP -запросы, методы, которые мы хотели блокировать, были поставлены, публиковать и удалять.
module Elasticsearch module Transport class Client if ENV['ELASTICSEARCH_ACCESS_MODE'] == 'readonly' def perform_request(method, path, params={}, body=nil, headers=nil) raise 'Elasticsearch is in readonly mode.' if method.to_s.match?(/PUT|POST|DELETE/) method = @send_get_body_as if 'GET' == method && body transport.perform_request(method, path, params, body, headers) end end end end end
Еще раз, мы также решили использовать переменную среды, чтобы определить, должны ли мы исправлять exector_request
метод Затем мы взяли эту переменную среды и добавили ее в наш сценарий Bash. Наш завершенный сценарий Bash выглядит так:
#!/bin/bash cd /application_path if [ "$1" = 'write' ]; then export DATABASE_URL="mysql2://write_username:write_password@host/db_name" export REDIS_ACCESS_MODE="" export ELASTICSEARCH_ACCESS_MODE="" else export REDIS_ACCESS_MODE="readonly" export ELASTICSEARCH_ACCESS_MODE="readonly" fi RAILS_ENV=production /usr/local/bin/bundler exec rails console
Этот сценарий гарантирует, что когда разработчик или поддержка открывают консоль, используя Консоль
Команда, по умолчанию, это будет читается. При необходимости они могут позвонить Консоль писать
Если им нужно обновить какие -либо данные. Несмотря на то, что очень легко открыть консоли записи, подавляющее большинство людей, которые люди работают в консолях Readonly. Консоли Readonly зарекомендовали себя много раз, спасая людей от глупых ошибок, просматривая данные о производстве.
Есть много других способов подхода к безопасности данных, когда речь идет о работе с производственными данными. Это всего лишь один подход и тот, который мы решили использовать в Кенне. Еще один очень популярный вариант — сделать реплику или клон ваших данных, а затем позволить людям запускать любые запросы, которые они хотят против этой копии или клона. Недостатком этого является то, что получение современной копии каждый раз, когда вам нужно, это может занять много времени в зависимости от размера вашего набора данных. Кроме того, клонирование одной базы данных, такой как MySQL, довольно просто. Однако, когда вы работаете с 3 различными хранилищами данных, например, мы делаем в Кенне, это гораздо больше усилий, чтобы воспроизвести все эти данные вместе.
В Кенне разработчики имеют возможность клонировать данные о производстве, но в настоящее время они доступны только в MySQL. Обычно клон MySQL используется только для проверки миграций высокого риска или сценариев, которые собираются изменить много производственных данных одновременно. Кроме того, мы обнаружили, что наша консоль Readonly отлично работала для нашего варианта использования, потому что большую часть времени разработчиков и поддержки просто хотят взглянуть на актуальные данные о производстве.
Надеюсь, вы нашли этот пост полезным! Как всегда, пожалуйста, дайте мне знать, если у вас есть какие -либо вопросы! 🤗
Оригинал: «https://dev.to/molly/how-to-setup-a-readonly-rails-console-1j1a»