🙌

docker buildkitを使いecsで本番モードでrailsを起動させる方法(master.keyの配送方法など)

2023/02/17に公開

ecsにrailsをデプロイする際にcredentials.yml.encに情報を書きこんでいる場合

credentials.yml.enc場合master.keyの情報も本番のecsに送らないと解読ができずエラーでrails コンテナが起動しない状態になってしまいます。

そこで今回はどのようにmaster.keyの情報を本番のecsに送れば良いかを説明していきます。

イメージにそのまま組み込めば良いのではないか?

特に何も指定しなければdocker buildする際にmaster.keyも一緒にイメージ化されてしまいます。
しかしmaster.keyまでイメージ化してしまうと、そのイメージを取得した誰でもredentials.yml.enc
中身を複合化し、機密情報を取得することができてしまいます。
NG!!!!!!!!

ではmsater.keyを.dockerignoreに入れてしまいイメージに含めなければ良いのでは?

確かに.dockerignoreにmsater.keyを含めればイメージには含まれないがcredentials.yml.encが複合化できないので、ここから情報を取得している実装の部分でエラーが発生して、docker buildに失敗してしまいイメージを作成できないのでそもそもデプロイできない😢

じゃあどうすれば良いか

やり方はいくつかあるが代表的になやり方は以下ではないかと思う

  • マルチステージビルドで行う
  • docker buildkitを使ってbuild時のみ一時的にmaster.keyをコンテナ側に送り、イメージには含めない
      docker buildkit機能が最近のバージョンではデフォルトで入っているのでこれを使うのが一番楽な気がする

ということでdocker buildkitでmaster.keyの情報をecsにセットする方法を説明します!

まずdocker buildkitを使いmaster.keyを含めずイメージを生成する方法

まず今回使用するdocker-compose.yml, entrypoint.sh, Dockerfileを記載します。

また事前に下記でmaster.keyを作成し、機密情報を記載しておく

EDITOR=vi bin/rails credentials:edit

ちなみに環境を指定して作成することもできる

bin/rails credentials:edit --environment development

docker-compose.yml

version: "3.9"
services:
  db:
    image: postgres
    volumes:
      - postgresql_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: password

  web:
    build: .
    volumes:
      - ./web:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

volumes:
  postgresql_data:

entrypoint.sh

#!/bin/bash
set -e

# 本番有効
bin/rails db:migrate

rm -f tmp/pids/server.pid && bin/rails s

# 今回CMDコマンド使わないのでコメントアウト
# exec "$@"

Dockerfile

FROM ruby:3.0

ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
ENV DEBCONF_NOWARNINGS=yes
ENV TZ Asia/Tokyo
ENV RAILS_ENV production
ENV BUNDLE_DEPLOYMENT true
ENV BUNDLE_WITHOUT development:test
ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_LOG_TO_STDOUT true

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
    && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
    && apt-get update -qq \
    && apt-get install -y cron \
    && apt-get install -y nodejs yarn postgresql-client

RUN rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY web/Gemfile /app/Gemfile
COPY web/Gemfile.lock /app/Gemfile.lock
RUN bundle install

# 本番用
COPY web/yarn.lock /app/yarn.lock
COPY web/package.json /app/package.json

COPY ./web /app
### ここのtargetでコンテナのどこのディレクトリファイルにidで指定したファイルを送るかを設定する
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true rails assets:precompile \
&& yarn install --production --frozen-lockfile \
&& yarn cache clean \
&& rm -rf /app/node_modules /app/tmp/cache

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true 

上記の部分でapp配下のconfig/master.keyにidがmaster_keyで送られてきたファイルを一時的に設置するかを指定する

そして下記のコマンドを使ってdocker fileをbuildする
ただしコマンドはrailsのトップディレクトリーで実行している前提で書いてあるので
srcは./config/master.keyを指定してる

docker buildx build --secret id=master_key,src=./config/master.key -t ビルドイメージ名 .

id=master_keyを指定してbuildしているので、srcの./config/master.keyがDockerfileの
app/config/master.keyに一時的に送信されてbuildすることができる。

イメージにmaster.keyを含めずbuildはできたがecsでどのようにこのmaster.keyの情報を送れば良いのか

これはrailsガイドを見ればわかる!
railsガイドのmaster.keyの部分を見ると環境変数にRAILS_MASTER_KEYを設定すれば
master.keyではなく環境変数の方の値をみて複合化しますよと書いてあるので
ecsにはタスク定義でRAILS_MASTER_KEYを設定すれば良いです!
https://railsguides.jp/configuring.html#config-require-master-key

設定する部分はタスク定義の環境変数の部分に設定すればよい

ただ直接環境変数をタスク定義に打ち込むよりもパラメーターグループ経由で送る方がよりセキュアーです
方法は下記を見てください
https://dev.classmethod.jp/articles/ecs-secrets/

Discussion