Capistrano 3 で secrets.yml をどう配置するか

2015/06/16

約1年10ヶ月ぶりの「Rails Tips」です。

今回は、Capistrano 3 で Rails アプリケーションをデプロイする時に、secrets.yml をどう扱うか、というお話しをします。

secrets.yml は Rails 4.1 で導入されたファイルです。その名の通り、秘密の情報を記録するためのファイルです。Facebook の API Key などを記録してもいいのですが、今回の話は secret_key_base に限定します。

このファイルの扱いが面倒なのは、次の3つの理由によります:

  1. 秘密の情報なので Git リポジトリにコミットできない。
  2. デプロイ対象のすべてのサーバーに同一内容のファイルを配置しなければならない。
  3. (セッションが切れてしまうので)運用中は原則として内容を変更できない。

早速ですが、私のやり方を紹介します。lib/capistrano/tasks ディレクトリ(なければ作ってください)に新規ファイル secrets_yml.rake を次のような内容で作成してください。

namespace :deploy do
  desc "Upload secrets.yml to the shared/config directory."
  task :secrets_yml do
    unless File.exist?('tmp/secrets.yml')
      secrets = { fetch(:stage).to_s =>
        { 'secret_key_base' => SecureRandom.hex(64) } }
      File.open('tmp/secrets.yml', 'w') do |f|
        f.write secrets.to_yaml
      end
    end

    on roles(:app) do
      unless test "[ -f #{shared_path}/config/secrets.yml ]"
        unless test "[ -d #{shared_path}/config ]"
          execute "/bin/mkdir -p #{shared_path}/config/"
        end
        upload! "tmp/secrets.yml", "#{shared_path}/config/secrets.yml"
      end
    end
  end
end

そして、config/deploy.rb に次の記述を加えます。

set :linked_files, %w{ config/secrets.yml }

こうすれば、Capistrano が shared/config/secrets.yml に対するシンボリックリンクを current/config ディレクトリに作成してくれます。

ちなみに、私の config/deploy.rb では次のような記述になっています。

set :linked_files, %w{ config/database.yml config/secrets.yml }

データベース接続設定のファイル database.yml もシンボリックリンクされる設定です。

準備作業は以上です。デプロイ先に shared ディレクトリが存在する状態で、次のコマンドを実行すれば、デプロイ対象のすべてのサーバーに対して同一の secrets.yml が配置されます。

$ bin/cap production deploy:secrets_yml

うまく配置できたら、ローカルの tmp ディレクトリにある secrets.yml は削除しておきましょう。

ところで、デプロイ対象のサーバーを新設する時には注意が必要です。そのまま上記のコマンドを実行すると、既存のサーバー群と新設のサーバー群との間で secrets.yml の内容が異なってしまいます。secret_key_base の値はセッションの暗号化に使われるので、すべてのサーバーで共通していなければなりません。

サーバーを新設するときは、既存の secrets.ymltmp ディレクトリにダウンロードしてからデプロイを行ってください。

なお、環境変数 SECRET_KEY_BASE を使ったデプロイ方法もネットで紹介されていますが、かえってややこしくなるように私には思えます。