hiroki-saoyun’s blog

40歳でも夢くらい持つよね!!プログラミング勉強中!

Encrypted Credentials②

マスターキーの管理

Railsではアプリ作成時に、Gitの管理から外すように設定されています。

.gitignore

# Ignore master key for decrypting credentials and more.
/config/master.key

上記のようにプッシュしてしまわないように設定されています。

ただ、チーム開発の時はマスターキーを共有しないとcredentials.yml.encの中身を見れないので、どのように共有するのかを書いていきます。

ローカル開発環境でのマスターキーの共有方法を確認

まずは、Slack等でconfig/master.keyの内容を共有します。

そして他のメンバーはクローンしたアプリケーションのconfigフォルダに新規で「master.key」ファイルを作成し、Slack等で共有した内容をコピーします。

本番環境でのマスターキーの扱い方を確認

作成したアプリケーションをCapistranoを使ってデプロイしても、本番環境のアプリケーションはcredentialsを読み込むことができません。

なぜならGit Hubへマスターキーがプッシュされないので、EC2にもプルされません。

本番環境でcredentialsを使うための手順

本番環境でcredentialsを使えるようにするため、環境変数にマスターキーを設定する必要があります。

etc/environmentsファイルに記述を行う事で、環境変数を設定することができます。

ターミナル

$ ssh -i ~/.ssh/(pemファイル名) ec2-user@(EC2のElastic IP)
[ec2-user]$ sudo vim /etc/environment

iキーを押して編集していきます。

/etc/environment

RAILS_MASTER_KEY='master.keyの値'
# config/master.key」の値をコピーして貼り付けます

これで設定はできたので、ログインし直します。

[ec2-user]$ exit
$ ssh -i ~/.ssh/(pemファイル名) ec2-user@(EC2のElastic IP)
[ec2-user]$ env | grep RAILS_MASTER_KEY

マスターキーの内容が表示されればうまくいっています。

Encrypted Credentials①

Encrypted Credentialsとは

Rails5.2から導入され、秘密情報を管理する機能です。外部に公開されたくない値はcredentials.yml.encというファイルでまとめて管理し、暗号化・復号にはmaster keyが必要になります。

credentialsの使い方

credentials.yml.encは普通に編集することができません。まずは編集するための準備を行います。

VSCodeでcredentialsを編集できるようにしていきます。

VSCodeで、「Command + Shift + P」を同時に押してコマンドパレットを開きます。

続いて、「shell」と入力します。そして「PATH内に'code'コマンドをインストールします」という項目が表示されるので、それをクリックします。

credentialsを編集

ターミナル

# アプリのディレクトリにいることを確認して
$ EDITOR='code --wait' rails credentials:edit

そうすると下記のように表示されます。

# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: dcb9317dcd2d42d9e045a2cd00c20df0b8109・・・

コメントアウトになってる部分を外して保存します。

yamlファイルの記述方法 yamlファイルではインデントが意味を持っています。ネストをさせる場合は、上のコードの2,3行目のようにスペース2つのインデントを入れるようにします。

credentialsの内容を確認

ターミナル

$ rails c
$ Rails.application.credentials[:secret_key_base]
$ Rails.application.credentials[:aws][:access_key_id]

carrierwave.rb

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.credentials[:aws][:access_key_id],
    aws_secret_access_key: Rails.application.credentials[:aws][:secret_access_key],
    region: 'ap-northeast-1'
  }
end

master.keyとは

config/master.keyに記載されいる値のことです。記載されていればcredentials.yml.encファイル を先ほどみたいなに編集することができます。

そのほかに、「環境変数」にキーを設定することでも同様の操作ができます。

マスターキーを環境変数にセット

config/master.key

b0705c15e27c0dd14e34fda・・・

コンソール

$ export RAILS_MASTER_KEY=(上の英数字)

※マスターキーとして使用する環境変数名は必ず「RAILS_MASTER_KEY」にする必要があります。

※「=」の前後にスペースが入らないよう注意です。

S3を使ってアップロード⑥

本番環境からS3にアップロード

本番環境の環境変数を設定

環境変数の設定ファイルを変更
# 本番環境
ターミナル
$ ssh -i [pem鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
(ダウンロードした鍵を用いて、ec2-userとしてログイン)
$ sudo vim /etc/environment
# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
AWS_ACCESS_KEY_ID='ここにCSVファイルのAccess key IDの値をコピー'
AWS_SECRET_ACCESS_KEY='ここにCSVファイルのにSecret access keyの値をコピー'
# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了
環境変数の設定を反映

ターミナル

# 本番環境
# 編集した環境変数を適用するために一旦ログアウトします。
$ exit
$ ssh -i [pem鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
# 環境変数が適用されているか確認しましょう。
$ env | grep AWS_SECRET_ACCESS_KEY
$ env | grep AWS_ACCESS_KEY_ID

デプロイにCapistranoを利用しているため、environmentというファイルに書き込んで環境変数の設定を行いました。

本番環境での環境変数読み込みの設定

config/secrets.yml

# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: cb2965bfebd75267542611a74ab612b9754f98・・・・・
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

test:
  secret_key_base: 7362cb8e960adf75f110e17bb4cd1f2d4edc3d・・・・・

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

このままではCapstranoで自動デプロイを行っても本番環境には送られないので、Capistranoの設定を変更します。 config/deploy.rb

# secrets.yml用のシンボリックリンクを追加
set :linked_files, %w{ config/secrets.yml }

# 元々記述されていた after 「'deploy:publishing', 'deploy:restart'」以下を削除して、次のように書き換え

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end

  desc 'upload secrets.yml'
  task :upload do
    on roles(:app) do |host|
      if test "[ ! -d #{shared_path}/config ]"
        execute "mkdir -p #{shared_path}/config"
      end
      upload!('config/secrets.yml', "#{shared_path}/config/secrets.yml")
    end
  end
  before :starting, 'deploy:upload'
  after :finishing, 'deploy:cleanup'
end

変更内容をデプロイ

GitHubにアップロードします。コミットしてGithubにプッシュ(publish)します。

自動デプロイを実行

ターミナル(ローカル)

$ bundle exec cap production deploy

S3を使ってアップロード⑤

画像のアップロード先をS3に変更

CarrierWaveによる画像のアップロード先がアプリ内のpublicフォルダでした。これをS3に変更します。

fog-awsをインストール

fog-awsをインストールします。

fogとは

画像をアップロードする際、外部のストレージを選択しアップロードするのを補助してくれるGemです。

Gemfile

gem 'fog-aws'

ターミナル

$bundle install

fogを使用するための設定

app/uploaders/image_uploader.rb

storage :file
↓
storage :fog

fogのアップロード先の設定

config/initializers直下に、carrierwave.rbというファイルを作成します。

config/initializers/carrierwave.rb

require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.secrets.aws_access_key_id,
    aws_secret_access_key: Rails.application.secrets.aws_secret_access_key,
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'ここにバケット名を入れます'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/ここにバケット名を入れます'
end

「ap-northeast-1」は、アジアパシフィック(東京)です。

安全にAWSのキーを扱えるよう設定

AWSのidやパスワードそのものは「環境変数」だけに設定します。

IAMユーザー設定時にダウンロードしたCSVファイル(2つ目のダウンロードファイル)を開きましょう。その中に、Access_key_IDとSecret_access_keyというカラムがあるので、こちらに書かれた値を設定していきます。

MacOSがCatalina以降の場合

ターミナル

# ローカル環境
$ vim ~/.zshrc

# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
export AWS_ACCESS_KEY_ID='ここにCSVファイルのAccess key IDの値をコピー'
export AWS_SECRET_ACCESS_KEY='ここにCSVファイルのにSecret access keyの値をコピー'

# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了

※ファイル編集時の注意

上記の設定は、現在の設定に「追加」してください。

ターミナル

# ローカル環境
# 編集した.zshrcを読み込み直して、追加した環境変数を使えるようにする
$ source ~/.zshrc
MacOSがMojave以前の方のローカル環境変数の設定

ターミナル

# ローカル環境
$ vim ~/.bash_profile

# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
export AWS_ACCESS_KEY_ID='ここにCSVファイルのAccess key IDの値をコピー'
export AWS_SECRET_ACCESS_KEY='ここにCSVファイルのにSecret access keyの値をコピー'

# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了

ターミナル

# ローカル環境
# 編集した.bash_profileを読み込み直して、追加した環境変数を使えるようにする
$ source ~/.bash_profile

secrets.ymlの設定

config/secrets.yml

# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: cb2965bfebd75267542611a74ab612b9754f98・・・・・
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

test:
  secret_key_base: 7362cb8e960adf75f110e17bb4cd1f2d4edc3d・・・・・

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

この2行を追記します。

.gitignoreを編集

「.gitignore」というファイルに設定を行うことで、Gitの管理下から除外することができます。

.gitignore

# ファイルの最下部に下記を追記
config/secrets.yml

ターミナル

$ git rm --cached config/secrets.yml
# アプリのあるディレクトリで行います

S3を使ってアップロード④

S3で保存先を用意

S3でファイルがアップロードされる領域を準備します。

S3を利用してバケットを作成

S3のページの左上の「バケットの作成」をクリックします。

バケットは、名前とリージョンを決めるだけで作成できます。

バケット名は任意の名前で、リージョンは「アジアパシフィック(東京)」を選択します。

次の画面では変更は必要ないので、そのまま「次へ」をクリックします。

続いてセキュリティの設定を行います。今回はバケットポリシーを使用してセキュリティ設定を行いますので下の2つにチェックを入れて、「次へ」をクリックし(上3つはチェックしない)、そして次の画面で「バケットを作成」をクリックします。

バケットポリシーの設定を行っていきます。IAMのページの「ユーザー」→「さっき作成したユーザー名」をクリックします。IAMユーザーの情報が表示されるので、「ユーザーのARN」をコピーしておきます。

次に、バケットポリシーの設定を行います。S3のページの「さっき作成したバケット」→「アクセス権限」→「バケットポリシー」をクリックします。

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "Policy1544152951996",
    "Statement": [
        {
            "Sid": "Stmt1544152948221",
            "Effect": "Allow",
            "Principal": {
                "AWS": "************①****************"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::************②**********"
        }
    ]
}

①に「ユーザーのARN」、②に「バケット名」を記述します。

最後に保存して終了です。

S3を使ってアップロード③

セキュリティ対策③

git-secretsをインストール

ターミナルから、Homebrewを経由してgit-secretsを導入します。

git-secretsとは

誤操作でパスワードをGitHubにpushしてしまうような誤操作を防いでくれるツールです。 パスワードだと推定されるような文字列が含まれている場合は、そこで処理が中断される仕組みです。

ターミナル

$ cd ~/
$ brew install git-secrets

ターミナル

$ git secrets --install
# 設定を適用したいリポジトリに移動して、git-secretsを有効化します

git-secretsの条件を設定

ターミナル

$ git secrets --register-aws --global
# アップロードしたくないAWS関連の秘密情報を一括で設定することができます

ターミナル

$ git secrets --list
# git-secretsの設定を確認することができます

今後作成する全てのリポジトリにgit-secretsが適用

ターミナル

$ git secrets --install ~/.git-templates/git-secrets
$ git config --global init.templatedir '~/.git-templates/git-secrets'

GitHub Desktopからgit secretsを利用できるようにします。

GitHub Desktop経由でgit secretsを利用する場合は、追加の設定をします。この時、Github Desktopがapplicationフォルダに存在している必要があります。

ターミナル

$ sudo cp /usr/local/bin/git-secrets /Applications/GitHub\ Desktop.app/Contents/Resources/app/git/bin/git-secrets

※上記コマンドでNo such file or directoryのエラーがでる場合は ターミナル

$ sudo cp /usr/local/bin/git-secrets /Applications/GitHub\ Desktop.app/Contents/Resources/git/bin/git-secrets

S3を使ってアップロード②

セキュリティ対策②

IAMユーザーの利用

IAMユーザーでログインできるようにしていきます。

IAMユーザーとは

IAMユーザーは、AWSのサービスの1つです。

AWSで作ったアカウントの使用できる機能を制限したユーザーのことです。

IAMユーザーを作成します

IAMのページの「個々のIAMユーザーの作成」→「ユーザーの管理」→左上の「ユーザーを追加」をクリックします。

そしてユーザー名を入力し、「プログラムによるアクセス」にチェックを入れ、「次のステップ:アクセス権限」をクリックします。

「既存のポリシーを直接アタッチ」から「AmazonS3FullAccess」にチェックを入れ、「次のステップ タグ」をクリックします。

次は何もせずに、「次のステップ: 確認」を押し、最後に確認して、「ユーザーの作成」をクリックします。

※この時「アクセス権限の境界:アクセス権限の境界が設定されていません」という表示が追加でされていることもありますが、設定に問題はありません。

ユーザーの作成が完了しました。

※忘れずに認証情報をダウンロードしておきます。(.csvのダウンロードってやつ)

IAMユーザーのパスワードを設定

IAMのメニューから作成したIAMユーザーをクリックします。「認証情報」のタブをクリックし「コンソールのパスワード」欄の管理 をクリックします。

「コンソールのアクセス」の欄は「有効化」、「パスワードの設定」の欄は「自動生成パスワード」にチェックを入れ「適用」をクリックします。

※ここでも忘れずに認証情報をダウンロードしておきます。(.csvのダウンロードってやつ)

これでIAMユーザーでログインができるようになります。

IAMユーザーも二段階認証

ルートユーザーでログインしなおします。

IAMのユーザー選択画面から先ほど作成したユーザー名を選択し遷移したページ先で、「MFAデバイスの割当」の欄の「管理」をクリックします。

あとは、ルートユーザーの時と同じように二段階認証の設定をします。