本番環境でRubyGems.orgを使うべきでない理由と、自前gemホスティングの始め方
本記事は、gemを自前でホストする方法を解説するコラム+ハウツーガイドです。
最初に断っておきます。gemは素晴らしいものであり、RubyGems.orgも優れたサービスです。
……しかし最近、アプリに新しいgemを追加するたびに、なぜか不安な気持ちになるようになりました。考えてみれば考えるほど、私たちのgemの使い方は単なる欠陥どころか、いつ爆発してもおかしくない時限爆弾なのではないかと思うのです。
ソーシャルエンジニアリングの実証実験
数日前、RubyNationというカンファレンスで、Ben Smithによる「Hacking With Gems」という印象的な講演がありました。
gemを開発するためのハッキングではありません。gemそのものを攻撃経路(アタックベクター)として利用するハッキングです。
彼は興味深い実験を行いました。
カンファレンスに参加された方なら、GitHubのステッカーなどのノベルティのそばに、美しく印刷されたカードの山が置いてあったのをご記憶かもしれません。
カードにはたった一言、こう書かれていました。gem install rubynation。そして、参加者の約10%が実際にこのコマンドを実行したのです。
あのgemが「しなかった」こと
このgemはいくつかの有用な動作をしていました。しかし、それ以上に興味深いのは「やらなかったこと」です。
このgemは、次のようなことはしませんでした。
gemcutterのドットファイルからRubyGems.orgの認証情報を盗み出すこと
平文のパスワードを傍受し、Railsの /public ディレクトリに保存すること
システムに秘密のSSHアカウントを追加すること
しかし、やりようはいくらでもありました。信じられないなら、Ben本人に確かめてみてください。
これは恐れるべき話です
もう一度、しっかり頭に刻み込むために繰り返します。
約25人——そう、プロのコンピュータープログラマーが、自分の開発マシン上で任意のコードを実行するよう仕向けられたのです。中にはroot権限で実行してしまった人さえいました。
これらの方々を揶揄したいわけではありません。これこそが、Rubyコミュニティではごく普通に見られる光景なのです。
なぜこんなことが起きたのか
人はgemを無条件に信頼しています。
たいていの場合、ちゃんと動くから。
Rails自体がgemだから。
Aaron Patterson、Steve Klabnik、Yehuda Katzといった著名な開発者たちがメンテナンスしているから。
しかし、見ず知らずの人を信用し始めた瞬間に問題が生じます。
gem install rubynation を、gem install rails と同じ感覚で何のためらいもなく入力してしまう——そこに問題があります。
正直に言いましょう。誰でも一度は経験があるはずです。私たちは怠惰であり、gemはあまりに手軽なのですから。
責任はRubyGems.orgにあるのではない
RubyGems.orgの罪は、間違ったことを極めて簡単に実行できてしまう点にあります。検証されていないコードをサーバー上で走らせてしまうこと。サーバー上で動くコードの変更に気づかないまま過ごしてしまうこと。
だからこそ私は提言したいのです。本番環境ではRubyGems.orgを使うのをやめよう、と。
解決策
署名だけでは不十分
誰もが自分のgemに署名すべきです。しかし、署名だけでは足りません。署名が保証するのは公開者の身元だけ。その人が善良なのか、悪意を持っているのか、あるいは中立なのかまでは教えてくれないのです。
誰も救いには来てくれない
理想的な世界なら、「良質であることが確認済み」のgemバージョンを配布してくれる信頼できる組織が存在するはずです。
それに抵抗を感じるなら、DebianがLinuxに対して同様の仕組みを提供していることを思い出してください。それでもまだ抵抗があるなら……ええ、私のブログを読んでくださっているだけで光栄です、ストールマン氏。
なぜ「理想の世界で」と表現するのか。それは、他の選択肢が膨大な作業を必要とするため、私自身はやりたくないからです。
……どなたかYC(Y Combinator)志望の方、ぜひこれを事業化してみてはいかがでしょうか?
唯一現実的な選択肢:DIY
残念ながら、私たちはこの臭くて古い現実世界で生きていかなければなりません。gemを完全にコントロールする唯一の現実的な方法は、次の2つです。
コードに悪意(裏切り)がないかレビューする
gemを自分でホストする
幸い、自前のgemホスティングは簡単です。以下で具体的な手順をお見せしましょう。
自前でgemをホストする方法
魔法ではない
gem「サーバー」とは、要するにWeb上に置かれた静的ファイルの集まりにすぎません。どこでもホストできます。S3やDropbox上でも構いません。
テストベンチとしてRailsアプリを作成する
ここでRailsを使う唯一の理由は、すぐに使えるGemfileが用意されるからです。このアプリ自体は何も行いません。
$ rails new myapp
$ cd myapp
.gemファイルをダウンロードする
次のBundlerコマンドで、Gemfile.lockが参照するすべての.gemファイルをダウンロードし、/vendor/cacheに格納できます。
$ bundle package
$ mkdir /tmp/gem_server
$ mv vendor/cache/ /tmp/gem_server/gems
「サーバー」用ファイルを生成する
.gemファイルが入ったディレクトリを配信可能な状態にするには、gem generate_indexコマンドを実行します。
$ gem generate_index -d /tmp/gem_server/
すべてオンラインに配置する
本番環境ではおすすめしませんが、例えば次のようにDropboxのPublicフォルダに置けば即座に公開できます。
$ mv /tmp/gem_server ~/Dropbox/Public/
Gemfileを編集してbundle update
「source」行を、rubygems.orgではなく新しいホストを指すように変更します。
# Gemfile
source 'https://dl.dropboxusercontent.com/u/12345/gem_server'
...
gem 'rails', '3.2.13'
成功です! Dropboxからgemを取得できています。
$ bundle update
Fetching gem metadata from https://dl.dropboxusercontent.com/u/12345/gem_server/.
Fetching full source index from https://dl.dropboxusercontent.com/u/12345/gem_server/
Using rake (10.1.0)
Using i18n (0.6.1)
Using multi_json (1.7.7)
Using activesupport (3.2.13)
おまけ:プライベートgemはHTTP Basic認証で保護できる
Gemfileを次のように記述するだけで、Basic認証付きの非公開gemサーバーを利用できます。
# Gemfile
source 'https://username:password@example.com/'
代替手段
この手法が環境に合わない場合は、より多機能な無料・商用のgemホスティングソリューションを選ぶこともできます。
Geminaboxはオープンソースのアプリケーションで、コマンドライン操作の手間を大幅に削減できます。
Gemfuryはプライベートgemホスティングサービスです。筆者も以前、クライアント向けの独自gemをホストするために利用しましたが、セットアップは簡単で、一度もトラブルに遭遇することはありませんでした。
-
Rubyのcaseステートメントの多彩な活用法と仕組みを徹底解説
Rubyでif / elsifを使おうとしている場面では、代わりにcaseステートメントを使うことを検討してみてください。この記事では、caseステートメントのさまざまな活用例と、その内部で実際にどのような仕組みで動作しているのかを解説します。 補足:他のプログラミング言語では、これはswitch文として知られています。 Rubyにおけるcaseステートメントの構成要素は以下の通りです。 キーワード 説明 case caseステートメントの定義を開始します。処理対象となる変数を受け取ります。 when マッチ可能な各条件が、1つのwhen句に相当します。 else どの
-
受信トレイを空にすべきか?――Inbox Zeroに疑問を投げかける
数年前、同僚とメールについて話したことがあります。彼女の受信トレイには何万通ものメールが溜まっていました。なぜ整理しないのかと尋ねると、彼女は的確な指摘を返してきました。「探したいものは検索すればすぐ見つかるのに、わざわざ時間と労力をかけてメールを仕分ける必要があるのか?」と。 Inbox Zero(インボックス・ゼロ)は、多くの生産性向上の専門家が支持する概念です。定期的に受信トレイを空にし、必要なメールはフォルダへ保存、残りは削除する。受信トレイはメールの一時的な受け入れ場所であって、永久的な保管場所ではない、という考え方です。美しい概念であり利点もありますが、ある意味では、郵便の時代の