Heroku上で扱う画像ファイルなどは、アプリがデプロイされるか、
アプリが再起動(24時間に1回自動で行われる)される度に消えてしまう仕様です。
なので、アップロードされた画像を「AWS」というサービスに保存されるようにする事で
この問題を解決していきたいと思います。
#目次
①.AWSアカウントの作成
②.AWS上のセキュリティ対策
③.S3でバケット(保存先)を作成
④.画像がS3のバケットに保存されるように設定
それでは早速始めていきます!
##①AWSアカウントの作成
https://aws.amazon.com/jp/
にアクセスしてサインアップします。
注意点は、アカウントの種類は「パーソナル」を選択すること。
サポートプランは無料のベーシックプランでOK
ここまできたら、実際にサインインして確認します。
##②AWS上のセキュリティ対策
3つの設定を行います。
1.二段階認証の設定
2.IAMユーザーの作成
3.git-secretsの利用
###1.二段階認証の設定
Authyというアプリケーションを利用するので、
ますは「Authy」を自分のスマホにインストールします。
初期設定が終われば、次はAWSマネジメントコンソールにアクセスします。
ヘッダーからアカウント名をクリックし、メニューの中から 「マイセキュリティ資格情報」 を選択
モーダル画面が表示されたら「Continue to Security Credentials」 をクリック。
メニューの中の 「多要素認証(MFA)」 をクリックすると内容が展開されるので、「MFAの有効化」 をクリック
モーダル画面の中から「仮想MFAデバイス」が選択されているのを確認して、続行をクリック
→次の画面で「QRコードの表示」をクリックすると、QRコードが表示されます。
→この状態で先ほどの「Authy」アプリを起動し、「Accounts」にある「+」ボタンをタップ
→設定画面を終了すると、二段階認証用のパスワードが表示されるようになります。
ワンタイムパスワードなので、30秒経つと自動的にそのパスワードは無効になります。
このパスワードをAWSで入力します。
1つ目のパスワードを上の欄に、その次に表示されたパスワードを下の欄に入力
最後に「MFAの割り当て」をクリックして設定は完了
###2.IAMユーザーの作成
IAMユーザーとは、AWSのサービスの1つで、機能を制限したユーザーを作成できる機能のこと
※最初にAWSで作ったアカウントはルートユーザー
検索のフォームに「IAM」と打ち込み、出てきた検索結果からIAMのページに飛ぶ
遷移先のページで個々の「IAMユーザーの作成」をクリックし、「ユーザーの管理」をクリック
遷移先のページで「ユーザーを追加」をクリックすると下記の画面になりますので、
作成するユーザー名の入力と、「プログラムによるアクセス」にチェック
そのあとは右下の「次のステップ:アクセス権限」をクリックして進みます。
「既存のポリシーを直接アタッチ」から検索窓に「amazons3」と入力し、
「AmazonS3FullAccess」に設定後、右下の「次のステップ:タグ」をクリック
遷移後は何もせず「次のステップ: 確認」をクリック
最後に設定の確認をして、「ユーザーの作成」をクリック
これで「IAMユーザー」の作成が完了です。
最後に、忘れずに認証情報(.csv)をダウンロードしておきます。
####「IAMユーザーのパスワード」を設定
IAMのメニューから作成したIAMユーザーをクリック
→「認証情報」のタブをクリックすると以下のページに遷移するのでコンソールのパスワード欄の「管理」 をクリック
ルートユーザーの時と同じく、認証情報はダウンロードしておきます。
####作成したIAMユーザーでログイン
今作成したIAMユーザーでログインできることを確認してみます。
まずルートアカウントのサインアウトを行います。
続いて、先ほどダウンロードしたcredential.csvを開くと下記の情報が記載されている
User name
Password
Console login link
User name と Password を入力して、Console login link のURLにアクセス
その後の画面で正常にログインできれば成功です。
####ルートユーザーで再度サインイン
サインイン画面で「ルートユーザーのEメールを使用したサインイン」を選択。
二段階認証を経てログインできます。
####IAMユーザーも二段階認証に
IAMのユーザー選択画面から先ほど作成したユーザー名を選択し、
遷移したページ先で以下の「MFAデバイスの割当」をクリック
あとは ルートユーザーの時と同じ手順で二段階認証の設定を行う。
###3.git-secretsの利用
「git-secrets」は、誤操作でパスワードをGitHubにpushしてしまう防いでくれるツールです。
まずはターミナルから、Homebrewを経由してgit-secretsを導入。
% cd ~/
% brew install git-secrets
git-secretsが導入できたら、設定を適用したいリポジトリに移動し、git-secretsを有効化
% cd アプリケーション名 #開発中のアプリケーションディレクトリに移動
% git secrets --install
続いて、「どのようなコードのコミットを防ぐのか」を設定していきます。
この後の作業は開発中アプリケーションのディレクトリで実行します。
####git-secretsの条件を設定
下記のコマンドを実行することで、secret_key, access_keyなど、
アップロードしたくないAWS関連の秘密情報を一括で設定することができる
% git secrets --register-aws --global
現在のgit-secretsの設定は、下記のコマンドで確認することができる
% git secrets --list
secrets.providers git secrets --aws-provider
secrets.patterns [A-Z0-9]{20}
secrets.patterns ("|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)("|')?\s*(:|=>|=)\s*("|')?[A-Za-z0-9/\+=]{40}("|')?
secrets.patterns ("|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?("|')?\s*(:|=>|=)\s*("|')?[0-9]{4}\-?[0-9]{4}\-?[0-9]{4}("|')?
secrets.allowed AKIAIOSFODNN7EXAMPLE
secrets.allowed wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
これで、「git secrets --install」を行なったリポジトリでは、
コミット時にAWSの秘密情報を含んだコードがないかチェックされるようになりました。
「うっかりパスワードをGitHubに載せてしまった」という事態を防ぐことができるので、必ず設定を行う。
####今後作成する全てのリポジトリに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を利用してバケットを作成
S3で実際にデータが格納される場所のことを「バケット」と呼びます。
バケットの名前はアクセスするときのURLに使用されるため、
英数字で、まだ誰も付けたことがない名前を使う必要がある。
遷移後の画面で「バケットを作成」をクリックし、バケット名の入力とリージョンを設定。
リージョンは「アジアパシフィック(東京)ap-northeast-1」 を選択し「次へ」
次の画面ではそのまま「次へ」
遷移後の画面で、「パブリックアクセスをすべてブロック」のチェックを外し、
新規の〜、任意の〜 にチェックを入れ、最後に上段のオレンジ色の注意喚起箇所のチェックを入れる。
「次へ」を選択し「バケットを作成」で完了です。
####バケットポリシー
どのようなアクセスに対してS3への保存やデータの読み取りを許可するか決められる仕組み。
今回は、作成したIAMユーザーからのアクセスのみを許可するように設定します。
AWSのトップページから「IAM」と検索し、表示されたメニューをクリック
「ユーザー」を選択し、「ユーザー名」のところの先ほど作成したユーザー名をクリック
IAMユーザーの情報が表示されるので、必要な情報を取得。
後ほど「ユーザーのARN」が必要にるので、一度メモアプリなどに保存しておきます。
次に、バケットポリシーの設定を行います。
IAMの時と同じようにサービス一覧からS3を選びます。先ほど作成したバケットをクリック。
「アクセス権限」をクリックし、「バケットポリシー」をクリック
表示されるコード記述欄にポリシーの入力をします。
先ほどメモしておいた 「ユーザーのARN」を①に、「作成したバケット名」を②に記述します。
{
"Version": "2012-10-17",
"Id": "Policy1544152951996",
"Statement": [
{
"Sid": "Stmt1544152948221",
"Effect": "Allow",
"Principal": {
"AWS": "①"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::②"
}
]
}
書けたら右上の「保存」をクリック
※保存ボタンを押した直後に「このバケットに対してパブリックアクセスの〜」と出ていれば保存成功。
###④画像がS3のバケットに保存されるように設定
1.投稿機能の挙動確認
2.ローカル環境の画像保存先をS3に変更
3.本番環境の画像保存先をS3に変更
####1.投稿機能の挙動確認
下記2点ができていることを確認します。
・ローカル環境で画像投稿が出来る
・画像がデータベースに保存されている
####2.ローカル環境の画像保存先をS3に変更
以下の要領で進めていきます。
a.必要なGemをインストール
b.保存先を指定
c.環境変数を設定
d.正しく保存できるか確認
####a.必要なGemをインストール
下記Gemを追記し、bundle install
gem "aws-sdk-s3", require: false
####b.保存先を指定
development.rbを編集します。
画像の保存先を「:local」→「:amazon」に変更
config.active_storage.service = :local ←修正前
config.active_storage.service = :amazon ←修正後
storage.ymlを編集します。
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
amazon:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
region: ap-northeast-1
bucket: 自身のバケット名
(省略)
今設定した
「 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>」「secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>」
の部分は環境変数を読み込むための記述です。
####c.環境変数を設定
【MacOSがCatalina以降の場合】
ターミナルで以下のコマンド実行
vim ~/.zshrc
「i」を打ち込みインサートモードへ。下記のコードを貼り付けます。
export AWS_ACCESS_KEY_ID="ここにCSVファイルのAccess key IDの値をコピー"
export AWS_SECRET_ACCESS_KEY="ここにCSVファイルのSecret access keyの値をコピー"
完了したら、「escキー」→「: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の値をコピー"
完了したら、「escキー」→「:wq」の順で実行し、保存。
編集後は「.zshrc」を読み込み直す。
$ source ~/.bash_profile
####d.正しく保存出来るか確認
ローカル環境で開発中のアプリから画像投稿を行い、S3に保存されているか確認してください。
バケット名をクリックすると投稿した画像があるはずなので、投稿日時を確かめ、今投稿した画像であることを確認します。
###3.本番環境の画像保存先をS3に変更
以下の要領で進めます。
a.保存先を指定
b.Heroku上で環境変数を設定
c.正しく保存できるか確認
####a.保存先を指定
本番環境の設定ファイルを開き、画像がS3に保存されるように設定を変更します。
production.rbを編集
config.active_storage.service = :local ←修正前
config.active_storage.service = :amazon ←修正後
####b.Heroku上で環境変数を設定
Herokuで環境変数を扱うにはマスターキーの時と同様、「heroku config:setコマンド」を打つ必要がある。
ターミナル(開発中のアプリ)で実行
heroku config:set AWS_ACCESS_KEY_ID="ここにCSVファイルの「Access key ID」の値をコピー"
heroku config:set AWS_SECRET_ACCESS_KEY="ここにCSVファイルの「Secret access key」の値をコピー"
環境変数が正しく設定できているかを確認するためにターミナル(開発中のアプリ)で下記のコマンドを入力
% heroku config
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
がそれぞれ設定されていたら成功。
編集内容をコミット。(ブランチを切っている場合は必ずmasterブランチにマージする)
ターミナル(開発中のアプリ)で下記のコマンドを実行し、編集した内容をHerokuに反映。
% git push heroku master
このコマンドにより、herokuがリモートリポジトリのmasterブランチを参照することが出来る。
####c.正しく保存できるか確認
本番環境で、開発中のアプリから画像投稿を行います。
そのためには以下の方法で「Web URL」を確認する必要がある。
以下のコマンドをターミナル(開発中のアプリ)で実行することで、
Herokuにデプロイされたアプリケーションの情報を見ることができる。
% heroku apps:info
「Web URL: 〜」の部分を確認できたら公開されたページにアクセスし、画像投稿をします。
その後、AWSトップページからS3にアクセスし、バケットにファイルが保存されているか確認します。
バケット名をクリックすると投稿した画像があるはずなので、投稿日時を確かめ、今投稿した画像であることを確認します。
以上です。お疲れ様でした。