セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

【terraform+capistrano+itamae】Railsのアプリケーションをawsにデプロイした時の備忘録②


前回terraformawsの構築を行いました。

thinline196.hatenablog.com

Capistrano

itamaeを使用して、環境の構築も同時に学習したかったのですが、あまりにも学習コストが高くなりそうだったので、サーバのrbenv,nginxmysqlのインストールはまずは手動で行いました。bundlerGemfile.lockを参照して同じバージョンを入れるのが望ましいかも?

デプロイプロジェクトで使用しているgemが要求する物に関しては適宜入れていきます。ImageMagickとか。本当はitamaeでその辺りもカバーします。バージョン等は各環境に合わせて。

参考サイト

以下、設定ファイルの説明のみ書いていくので、手順が知りたい人はリンク先をおってください。 (デプロイ編①)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで - Qiita

AWS RailsアプリケーションのCapistranoによるデプロイ - Qiita

使用Gem

capistrano3-unicornは使用せずにやりました。

#Gemfile
group :development, :test do
 gem 'capistrano'
 gem 'capistrano-bundler'
 gem 'capistrano-rails'
 gem 'capistrano-rbenv'
end

group :production, :staging do
  gem 'unicorn'
end



bundle exec cap installを実行

capistrano設定

Capfile



config/deploy/production.rb

このファイルは大枠の設定ファイルみたいなイメージ。
serverにはデプロイする先のアドレスと、そこにどのロールのタスクを実行するか指定する。今回でいうとapp``db``webと指定したタスクが指定アドレス上で実行される。次に紹介するconfig/deploy.rbにてタスクごとにロールを振っているのがわかる。



config/deploy.rb

このファイルが上から実行されるみたいなイメージだと良いかも?上から変数を定義して下でタスクを順に実行するみたいな。例えば上のconfig/deploy/production.rbdbを指定しなかった場合、db_createの中身は実行されない。

repo_urlではGitPersonal API tokenをxxxxに指定することでプライベートリポジトリの物もデプロイ可能。記事の下の方に参考サイトを貼っておきます。



lib/capistrano/tasks/unicorn.rb

unicornのタスクを記述したファイル。上のconfig/deploy.rb内のunicorn:restartが呼び出しているのはこのファイルに定義したタスク。



config/unicorn/production.rb

unicornの設定ファイル。capistranoとの関連はないが、デプロイ先のディレクトリについての関係は同じにしておく。



nginx,mysql等の設定については、参考サイト先を参照してください。基本的にこの辺りはのちにitamaeでカバーしようと思うので、入れるコマンドや手順はメモっておくとitamaeの導入が楽かもです。



環境変数

configgemを使用しました。 ローカルにはconfig/secrets.yml

# config/secrets.yml(ローカル)
production:
  secret_key_base: <%= Settings.production[:secret]%>

としましたが、他のページにもいくつか同じように指定している箇所があるかと思います。上のconfig/deploy.rbの設定で、shared/config/settings/production.ymlシンボリックリンクを生成することを宣言したため、そちらに内緒にしたい値を定義していきます。

# shared/config/settings/production.yml (aws)
database:
  user_name: 'root'
  password: 'hogehoge'
production:
  secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
mail:
  address: 'test@example.com'
  password: 'xxxxxxxxxxxxx'

こんな感じ。

awsRDBを使用する

config/database.ymlhostawsに指定しなければいけない。なので、awsインスタンス内でyum install mysql-serverをやる必要はない。(aws内にRDBインスタンスを作っていない場合は例外)

EC2とRDSでrailsを動かす - Qiita



プライベートリポジトリからdeployする

Capistrano3でgithubのプライベートリポジトリを簡単にデプロイする方法 · polidog lab++

CapistranoでGitHubにアクセスする際のネットワークプロトコルをhttpsにする - Qiita



デプロイ実行

$ bundle exec cap production deploy



その他対処など..

assets:precompileエラー

ActionView::Template::Error (The asset "application.css" is not present in the asset pipeline.):

上のエラーはcss等が未コンパイルのためエラーが起こる。自分でコンパイルする必要があるが、yarnが必要になるため、下記事を参考に導入後次のコマンドを入力する。

エラー解決の参考 Rails5でnginx+pumaでproduction環境を構築する · atwata developer blog
最新のnodejsyarn導入の参考 EC2にyarnをインストールする|新卒エンジニアの開発日記

bundle exec rake assets:precompile RAILS_ENV=production また、静的ファイルが読み込めない場合以下をconfig/environments/production.rbに記述

  # config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? コメントアウト
  config.public_file_server.enableda = true



ImageMagic問題

gemのrmagicのバージョンが3だと、ImageMagicのバージョン7に2019年6月現在対応していない。が、6系も低すぎるとエラーになる。

ImageMagicインストール参考サイト

Install ImageMagick from source on Amazon Linux · GitHub


ImageMagicバージョンダウンロードサイト Index of /download

db:migrate

参考にしたサイト通りにやっていればエラーなど出ないが、db:migrateが実行されない現象にぶつかった。 config/deploy/production.rbserverのロールとしてdbを含めていなかったため、dbロールに割り当てられていた、マイグレーションの実行がされておらずテーブルが生成されていなかった。(itamae導入前なので、テーブル自体は手動で生成した)

Capistrano の db ロール - akishin999の日記



デプロイ時エラー

git stdout: Nothing written
git stderr: fatal: Not a valid object name
tar: これは tar アーカイブではないようです
tar: 前のエラーにより失敗ステータスで終了します

=>Capfileで指定したデプロイするブランチ名が違っていた。

sharedディレクトリ等の作成

あらかじめディレクトリを生成しておく場合、権限を正しくしておかないとcapistranoが書き込めなくてエラーがでる。terraformで使用したアカウントとcapistranoで使用するアカウントの権限の差に注意しておくこと。特に、ec2-userより権限の小さいユーザを生成してから、capistranoでデプロイするとだいたい書き込めないので注意。次回のitamae編ではその辺りにも注意して進めます。
次の記事はこっち

thinline196.hatenablog.com



【terraform+capistrano+itamae】Railsのアプリケーションをawsにデプロイした時の備忘録①

参考サイト

基本的にこちらを参考にしているため、こちらを見れば諸々解決可能です。本記事は備忘録なので見にくいかも。

tech.recruit-mp.co.jp

kenzo0107.hatenablog.com

terraform

terraformとは

インフラストラクチャ定義ツール に分類されるツールで、クラウド上のリソースを定義ファイルの状態になるように生成・操作してくれます インフラの構成を宣言的に定義できるところが特徴で、構築手順を書くのと違って構成定義のみに集中することができます 10分で理解するTerraform - Qiita

設定(main.tf)

プロジェクトルートに以下の2つのファイルを生成。 main.tfには生成するインスタンスや周辺の設定を書きます。インフラ周り?
aws_key_pairにはこちらからssh接続するために設定したい公開鍵を登録します。


terraform.tfvarsにはGitにのっけにくいキーの情報を書いて環境変数として扱えるようにします。



プロジェクトルートにて、以下のコマンドをうつ。

$ terraform init
$ terraform plan
$ terraform apply


terraform planで設定ミス等に気づける、はず。
以下の表示が出れば成功。

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

elastic_ip_of_calendar_web = xx.xxx.xxx.xxx


上のログに出力されたipにssh接続する。

$ssh ec2-user@xx.xxx.xxx.xxx


ec2-userawsのデフォルトで生成されるアカウント。main.tfで設定した鍵のペアが必要です。

capistrano編に続きます。 こちら

thinline196.hatenablog.com

【Rails】git-cz, rubocopなど初期導入での設定

新規のRailsのプロジェクト

を久しぶりに立ち上げた際に、git-cz等の導入方法を忘れていたので備忘録として残しておきます。

yarnの導入

yarnJavascriptのパッケージマネージャーです。brew等から入ると思います。

$ brew update
$ brew install yarn
$ export PATH="$HOME/.yarn/bin:$PATH"



npmのモジュールの導入

今回は諸々を入れます。これは、自分のRailsプロジェクトのルートディレクトリ直下で行いました。

$ yarn add --dev commitizen cz-customizable husky lint-staged



package.jsonに追記

すでにある設定に以下を追記します。

{
  "scripts": {
    "cz": "npx git-cz"
  },
  "lint-staged": {
    "(*.rb|Gemfile)": [
      "bundle exec rubocop --auto-correct --fail-level E",
      "git add"
    ]
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    },
    "cz-customizable": {
      "config": ".cz-config.js"
    }
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
}


lint-stagedには、対象にしたいファイルの拡張子と、それに対して行うコマンドを記述しておきます。

rubocop.ymlの設定

rubocop.ymlrubocop先生の設定を書くのですがこれは、個人でお好みでお願いします。

.cz-config.js

package.jsonにおいてcz-customizableは別途記述するとの設定を行ったので、同じくプロジェクトルートに.cz-config.jsを配置します。

'use strict';
module.exports = {
  types: [
    {
      value: 'feat',
      name: 'feat:     新機能',
      title: 'Features'
    },
    {
      value: 'fix',
      name: 'fix:      バグ修正',
      title: 'Bug Fixes'
    },
    {
      value: 'HOTFIX',
      name: 'HOTFIX:   致命的で緊急なバグ修正',
      title: 'Critical hotfix'
    },
    {
      value: 'UI',
      name: 'UI:       UIやスタイルの更新',
      title: 'UI'
    },
    {
      value: 'docs',
      name: 'docs:     ドキュメントのみの変更',
      title: 'Documentation'
    },
    {
      value: 'style',
      name: 'style:    フォーマットの変更\n            (コードの動作に影響しないスペース、フォーマット、セミコロンなどの変更)',
      title: 'Styles'
    },
    {
      value: 'texts',
      name: 'texts:    文字や文章の更新',
      title: 'Text and literals'
    },
    {
      value: 'i18n',
      name: 'i18n:     国際化',
      title: 'Internationalization'
    },
    {
      value: 'typo',
      name: 'typo:     タイプミスの修正',
      title: 'Typos'
    },
    {
      value: 'refactor',
      name: 'refactor: リファクタリングのための変更\n            (機能追加やバグ修正を含まない変更)',
      title: 'Code Refactoring'
    },
    {
      value: 'perf',
      name: 'perf:     パフォーマンスの改善のための変更',
      title: 'Performance Improvements'
    },
    {
      value: 'UX',
      name: 'UX:       ユーザーエクスペリエンス/ユーザビリティの改善',
      title: 'UX'
    },
    {
      value: 'test',
      name: 'test:     不足テストの追加や既存テストの修正',
      title: 'Tests'
    },
    {
      value: 'config',
      name: 'config:   設定の追加や変更',
      title: 'Configuration'
    },
    {
      value: 'build',
      name: 'build:    ビルドシステムや外部依存に関する変更\n           (スコープ例: gulp, broccoli, npm)',
      title: 'Builds'
    },
    {
      value: 'CI',
      name: 'CI:       CI用の設定やスクリプトに関する変更\n           (スコープ例:Travis, Circle, BrowserStack, SauceLabs)',
      title: 'CI'
    },
    {
      value: 'chore',
      name: 'chore:    その他の変更\n           (補助ツール、ドキュメント生成などのソースやテストの変更を含まない変更)',
      title: 'Chores'
    },
    {
      value: 'WIP',
      name: 'WIP:      作業中',
      title: 'WIP'
    }
  ],
  scopes: [
    // { name: '*' },
    // { name: 'admin' },
    // { name: 'exampleScope' },
    // { name: 'changeMe' }
  ],
  // it needs to match the value for field type. Eg.: 'fix'
  /*
  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },
  */
  // override the messages, defaults are as follows
  messages: {
    type: 'コミットする変更タイプを選択:\n',
    scope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n',
    // used if allowCustomScopes is true
    customScope: '変更内容のスコープ(例:コンポーネントやファイル名)(optional):\n',
    subject: '変更内容を要約した本質的説明:\n',
    body: '変更内容の詳細("|"で改行)(optional):\n',
    breaking: '破壊的変更についての記述(optional):\n',
    footer: '関連issueを追記 (例:"fix #123", "re #123")(optional):\n',
    confirmCommit: 'このコミット内容でよろしいですか?'
  },
  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix']
};

おまけ

最初に入れると便利なgem

gem "dotenv-rails" #envファイルで環境変数
gem "global" #定数管理
gem "kaminari" #pageing
gem "slim" #slim
gem "tilt" #slimのために

group :development, :test do
  gem "factory_bot_rails"
  gem "hirb" # コンソールちょっとみやすく
  gem "pry-byebug"
  gem "pry-doc"
  gem "pry-rails"
  gem "pry-stack_explorer"
  gem "rubocop", require: false
  gem "rubocop-rspec"
end

group :development do
  gem "annotate" #migrate時とかに自動でshemaをコメント
  gem "better_errors" #エラー見やすくするやつ
  gem "binding_of_caller" #エラー画面からコンソール操作
  gem "brakeman", require: false 
  gem "bullet" #N+1クエリ検出
  gem "bundler-audit" #セキュアじゃないgemを警告
  gem "html2slim" #erbとかhtmlをslimに変換(精度はわるい)
  gem "web-console", ">= 3.3.0"
end

【Mini Hardening】#3.3@FOLIOに参加してきた

Hardeneing

とは、与えられた環境を攻撃から護り続け、なるべくサービスを稼働させ続ける事が目的の競技です。調べればいろいろ出てきますが、本戦は8時間に渡って競技をするのに対しこちらは3時間の短縮版となっています。

内容

については、ネタバレ厳禁という事で残念ながら触れられません。が、おそらく全参加者が目を通したであろうこちらのブログは絶対に読んでおく価値はあると思います。

fkshom.hatenablog.jp

感想

この競技はおそらく運用を業務で行なっている方が圧倒的に強いと思います。なので初心者の方は競技中、競技後に圧倒的敗北感を感じます笑


が、元々このMini版は初心者のかたむけですし、主催者の方も"攻撃をもろに受ける状況を体感できる機会は少ないし、これを通じて勉強のバネにしてほしい"みたいな事をおっしゃられてました。

これから参加される方へ

上に貼ったブログ先にも書いてある事前準備はマストだと思います。ただ、知識がなかった僕なんかは、最初の1時間が過ぎた後は何をすればいいか路頭に迷ってしまいました。なので、競技中に常に監視しておくもの、そしてその手法を自分で調べておけば多少はチームの役に立てるのではないでしょうか?

【visudo】sudoers.d service(コマンド)の指定

visudo

username ALL=(ALL) NOPASSWD: /sbin/service nginx start

こんな感じ。コマンドを指定する時は、絶対パスで指定してあげないと、ダメです。 /bin/systemctlみたいな感じで。

参考サイト

visudoでsudo権限の設定をする際のメモ(sudoersの&#39;ers&#39;って何の略なんですかね?) - Qiita



余談

どうやら終端が改行じゃないとエラーが起こるらしいです。一番下の行だけ気にすれば良さそうな気はしますが、下の行がコメント文だったとしても改行していないとエラーになるっぽいです。
Chefでsudoersをいじったらsudoできなくなったの巻 - Qiita