dotenvで秘密情報を扱う件 〜 Ruby, PHP, PaaS, CI について 〜

.envファイルに環境変数を書いておく

dotenv って何かと一言で言うと Foreman の提供している .env ファイルから環境変数をセットする機能を Foreman 環境以外でも利用できるようにしたもの。

えーと。何のこと?って感じですね。

dotenv という言葉は意味する範囲がやや曖昧なんだけど、自分の場合は「.env ファイルに sh script のように環境変数を記述しておくと、アプリが実行時に自動的に環境変数として取り込むことができる系の機能の総称」と捉えている。

で、実装がそれぞれにある。いちばん有名な Ruby バージョンだと予想通り Dotenv gem で、他の言語でも似たようなものがいくつもある。

bkeepers/dotenv

なぜ.envファイルから環境変数をセットするのか

環境変数から設定を取得したり環境判別用の情報を取得しようという話は決して新しい話ではない。例えば Rails では以前から RailsEnv や RackEnv という環境変数を見て環境を切り替えるという機能があって、そのために Apache の httpd.conf に SetEnv とか書いたことのある人もいると思う。

つまり production では環境変数から情報を取得することができるというのは割とポピュラーな手法。しかし手元の開発環境ではこれらがセットされていないことが多く、設定用のコードで環境変数がセットされている場合とセットされていない場合を判別して処理する必要が出てきたりする。そうなると煩雑だしバグのもとになるし、環境変数をセットしつつ rails server を起動するのも面倒くさい。一度実行すれば履歴に残るだろうけど、そういう理解もコマンドライン環境への習熟度合いに大きく左右される。

そこでこの環境変数の扱いが抽象化されているといいよねとなって、.env ファイルから環境変数を自動でセットする方法が生まれた。書き方は sh script と同じ。rails server の起動のたびに環境変数をセットする必要もないし、楽ちん。

当初これを実現したのは Procfile を使って関連するプロセスを起動する Foreman だったようだ。しかしこの .env ファイルを扱う機能はプロセスの管理とは独立して便利なので Dotenv が生まれた。

cf. http://opensoul.org/2012/07/24/dotenv/

環境変数と秘密情報

なんでいま環境変数の話なのかというと、

秘密情報をどう扱うか?

が問題になるケースが増えてきたから。例えば AWS や Google はじめ各種 API を利用するのに key, secret, credential と呼ばれる秘密情報が必要になる。これら

秘密情報をアプリケーションコードの中、repositoryの中に直接置かずに利用したい。

直接 repository に入れてしまうと production と development で同じ秘密情報が利用されてしまったりするし、公開 repository で開発する場合や、private repository でも外部のパートナーと共有する場合はそもそも秘密情報を含むことはできない。

ということで環境変数経由でこういう情報は利用しましょうというのが最近の作法となっている。

cf. The Twelve-Factor App(日本語訳)

改めてdotenvと秘密情報

ということで、環境変数で秘密情報を渡すようにしてアプリや repository の中に入れないようにしましょう、そのために dotenv が使えるよということなんだけど、その時にこれを守っていないと台無しになってしまうのは、

.env は .gitignore しておくこと

これやらないとツールが増えるだけで、情報の扱いは変わらないので。

PaaS, CIと環境変数

自分で立てたサーバならアプリケーションの実行環境に環境変数をセットするのは自由にできるけど、昨今の Web 開発を支える便利サービス、PaaS や CI サービスはどうなっているのかと思い、ざっと調べてみた。

Heroku は Twelve Factor App という文書でアプリケーションを portable にするために環境依存の設定は環境変数を通じてセットしようと提唱しているように、Heroku はじめ各種 PaaS ではアプリケーションの実行環境に環境変数をセットする方法を提供している。とりあえず確認したところ Heroku, Mogok には Web UI から環境変数をセットする機能がある。

Sqale は 2015-04-05 時点では Web UI からの設定はできなくて、逆に .env ファイルを production で使うように奨めている。.env ファイルは基本的にプロジェクトルートに置くので、これは公開 repository では使えない方法である。そこで解決策として deploy ごとにクリーンになってしまわない領域に秘密情報を置いて、postinstall スクリプトで symlink を作るという方法を提供している。ただ ssh で作業する必要があり、Un*x 系サーバに不慣れな人にはちょっと向かない方法だ。また、この方法は ssh でアクセスできる人には秘密情報はバレてしまうということでもある。

Sqale - FAQ: 技術的な仕様に関する質問

EngineYard も Web UI はなくて Sqale のようにアプリケーション環境内の消えない領域にファイルを置く形のようだ。

Engine Yard CloudでPHPを利用する : Developer Center

CI については以前調べた時のついーとを貼付けておく。

あとこんなこと言ってる人がいた。

えーとまとめるとメジャーなCIサービスは環境変数を Web UI からセットできるようだ。Drone.io もできるってさ。

dotenv系ツール

最後はツールを紹介しておしまい。

Dotenv gem

この Dotenv gem は foreman のようにコマンドとしても使え、dotenv コマンド経由でアプリを起動すれば Ruby 以外の言語でも同じように .env から環境変数をセットできるようだ。

bkeepers/dotenv

使い方は、

1. require 'dotenv' して Dotenv.load(*args)

require 'dotenv-rails' してしまうと load は引数を受け取れないので注意。

2. dotenv bundle php -S localhost:3000

この場合は dotenv 経由で起動したプロセスに環境変数がセットされる。

direnv

Dotenv は ruby のコード内で .env からの読み込みを明記したり、dotenv コマンド経由でアプリケーションを起動する必要がある。

対して Direnv は rvm, rbenv が用意しているような、shell を hook して特定のディレクトリに入った時だけ特定の環境変数をセットすることができる Go 製のツール。

つまり、アプリケーションコード内で env のロードを明示する必要がなく、アプリケーションの言語に依存しない代わりに shell の設定が必要になる。

これは伝統的な PHP アプリ開発者には向いていないかも。あと、アプリケーションコード内に環境変数の設定に関する記述がなくなるので、そのノウハウの共有は十分注意して行う必要があるような気がする。

phpdotenv

vlucas/phpdotenv

..env が読み込めない時に例外が上がっちゃう。ちょっとちょっと。しかも超汎用的な InvalidArgumentError なのでハンドリングが難しい。なーーーんでそんなことするの。

php-dotenv

josegonzalez/php-dotenv

読み込みの記述が Dotenv gem に比べると冗長。

Laravel + Dotenv

Laravel は 4 の時点では自前で .env.php を扱っていたが、Laravel 5 では Dotenv を使うように変わっている。

うーん、簡単に Fatal Error になっちゃう方を採用したのね。なんか方法考えないとな。

あと、当然気づいてると思うけど npm にもある。 dotenv ま、イマドキだいたいどの環境でも使えるんだと思う。

SimpleTestをCIへ活かす

まず exit status を返す

昨日(2010-04-04)Integrity を教えてもらった。Integrity 自体は他のツールと違って testing framework との間をわざわざ取り持とうとはしていなくて、exit status さえ返せば判断できるっぽい。

ということでとりあえず普段使っている SimpleTest で exit status に test の結果を載せる方法を調べた。

exit( $test->run( $reporter ) ? 0 : 1 );

でイケる。

これだけ見るとなんのこっちゃって感じなので、次に TestSuite のコードを貼る。

exit status を返す TestSuite

Integrity を使おうと思ったら全テストの結果を exit status で返す必要がある。(はず。)そのためにまず全テストを回す TestSuite を作る。それが以下のコード。

わざわざ __FILE__ と比較して実行開始してるのは個々の test case と同じ書き方をしているため。っていうのと、普段使っている 1.0.0 は autotest に対応していないため。

こうしておくと test case を個別にテストできるし、test suite をまとめてテストすることもできる。個々のテストを回せる方が TDD の回転の速度を稼げる。回転重要。

うん。そんな感じ。

RestClient は 0.9 でヘッダが取れるようになってた

RestClient を散々持ち上げておきながら、最近ページの内容がほしい場合には open-uri をよく使っていました1。でも、いろんな方が2思っていながらなんとなく放置気味になっているキャッシュがやはり欲しいなぁと思ったときには open-uri だと困ります。ヘッダがほとんど取れないので。([2009-04-24追記] 嘘でした。URI().read.meta で取れました。)でもそのためだけに Mechanize はちょっとイヤなのです。そんなに機能要らないし。

どうしようと思っていたんですが、灯台下暗し。RestClient が 0.9 からヘッダ取れるようになってました。

rest-client 0.8.2 の場合

irb(main):001:0> gem 'rest-client', '< 0.9'
=> true
irb(main):002:0> require 'rest_client'
=> true
irb(main):003:0> r = RestClient.get( 'http://aligach.net/diary/' )
=> ...
irb(main):004:0> r.methods.grep( /headers/ )
=> []

rest-client 0.9.2 の場合、

irb(main):001:0> gem 'rest-client', '>= 0.9'
=> true
irb(main):002:0> require 'restclient'
=> true
irb(main):003:0> r = RestClient.get( 'http://aligach.net/diary/' )
=> ...
irb(main):004:0> r.methods.grep( /headers/ )
=> ["headers"]
irb(main):005:0> r.headers
=> {:cache_control=>"no-cache", :vary=>"User-Agent",
    :last_modified=>"Sun, 05 Apr 2009 00:33:07 GMT",
    :server=>"Apache/1.3.39 (Unix)", :x_pad=>"avoid browser bug",
    :content_length=>"30246", :content_type=>"text/html; charset=EUC-JP",
    :pragma=>"no-cache", :date=>"Mon, 06 Apr 2009 00:37:43 GMT"}

適当に整形してしまいましたが、要は headers というメソッドでヘッダの内容が Hash として取れます。うむ。便利になった。ちなみにリリースノートは

RubyForge: Rest Client: リリースノート

あ。require 'restclient' でイケるようになってる。まぁどっちみち gem の名前と合ってないんだけど;;

ところで今まであまり気にしていなかったのですが、RestClient.get の結果って、RestClient::Response オブジェクトなんですけど、これ、

irb(main):006:0> r.is_a? String
=> true

String なんですね。なるほど、それで irb 上でいきなり内容を確認できるのか。ってほんとにイマサラなわけですが。

cf.

rest-client が便利

  1. まぁ内容が欲しいんだから間違ってないんですが。 

  2. 自分を含めて 

今日は del.icio.us 始めました

うわーめっちゃ便利やわ(誰)

これも以前から使ったら便利じゃないかなぁと思いつつ放置していたものなんだけど、びっくりするくらい便利。シンプルでよさそうだなぁと以前から思っていた通り、使いやすい。タグの入力は、すでに誰かがタグ付けしてたら recommended や popular にリストアップされるのでそれをクリックするだけで済む。何も出てこないときはまっさらな大地を開拓していくような快感がある。

思ったより軽いのはたまたま調子がいいのか?1

いつまで続くか分からないけど、登録も編集も削除も少ない手間で行えるようにいろいろ工夫されていて気持ちがいいので、意外と続くかも。

  1. 検索してないだけだったっぽい。 

Bloglines の font-size を調整しまくり

やっと使いやすくなった。OSX での見た目しか考えてないので特に margin の辺りは逆効果の可能性もあり。

しかし、長いこと Sage で見てたから、本文のサイズは 100% じゃない方が一覧性が高くていいかもとか思い始めている自分がいる…。いやいや! 本文は 100% が基本だよ! と言い聞かせる。

あ。注釈が必要ですな。以下のユーザーCSS は Bloglines 上で全文を読むことを前提に組んだものです。それ以外の使い方をしている場合には適さないと思います。

@-moz-document domain( bloglines.com ) {
  body#subscriptions {
    font-size: 80% !important;
  }
  body {
    font-size: 100% !important;
  }
  pre {
    overflow-x: scroll !important;
  }
  div.logbar {
    font-size: 90% !important;
  }
  .searchbar {
    font-size: 85% !important;
  }
  .tabs {
    margin-top: .5em !important;
  }
  div.channel_nav {
    font-size: 90% !important;
  }
  .channel h1 {
    font-size: 130% !important;
  }
  .channel h2 {
    font-size: 110% !important;
  }
  .header_nav {
    font-size: 90% !important;
  }
  .content-main h3 {
    font-size: 120% !important;
  }
  p.author {
    font-size: 75% !important;
  }
  div.item_nav {
    font-size: 85% !important;
  }
  div.shortcuts {
    font-size: 90% !important;
  }
  div.homefooter {
    font-size: 80% !important;
  }
}

tiddlywiki とか試した影響かな、本文の投稿日時や更新日時の情報はマウスオーバーでうにょっと出てきた方が邪魔にならなくていいかなと感じる。

ちょっと意外な Terminal.app の落とし穴

cygwin に ssh 経由でログインしたときになんかちょこちょこ動きがおかしい。$TERM とか $LANG の設定かなと思うと

  • 同じ設定で Linux にログインしても大丈夫
  • 同じ設定で iTerm から cygwin に繋いでも大丈夫
  • 同じ設定で putty から cygwin に繋いでも大丈夫
  • つまり Terminal.app と cygwin の sshd の組み合わせでだけ起きる症状

ということで、どこかのツクリが違うんでしょな。ま、これは cygwin に ssh で繋ぐ方がイレギュラーだし、完全に CLI で使う分には問題なく使えるので、放置決定。iTerm はやっぱちょっと重たいので積極的に乗り換える気にはならない。(と言いつつバージョンが上がると喜んで落としてるんだけど :-)

Thunderbird 1.0.2 日本語版

Thunderbird - 迷惑メールにお別れを

気づかなかった。4月1日に出ていたとな。タイミング悪いよ!

例によって ryuzi_kambeの?D - Mozilla Thunderbird 1.0.2 日本語版リリース より。

sitecopy が sftp を公式にサポートしたのね

Changes in release sitecopy 0.15.0, 5 March 2005 (PGP signature)

  • Add SFTP support from Nobuyuki Tsuchimura using "protocol sftp".

ということです。これの何が嬉しいかっていうと、例えば rsync とか unison を ssh 越しに使うためにはそれに対応した shell で、それらのコマンドの利用を許可しておかないといけないけど、sftp しか使わない場合はそういう風に気を使わずに済むってこと。1だと思ってるけど違うのかな?2

sitecopy 0.15.0 は入れてるけど man が追随してないな。今度実験してみよう。その前にパッチ作者さんのページで使い方を確認してみませう

  1. 暗号化した認証と通信路を確保したファイル転送を行いたいけど、ssh は自由すぎて困るなぁ、という要求に応えるためにあれこれ管理者は悩んでいるっていう前提を共有できてないと全然通じないな、この話は。 

  2. もちろん rsync や unison を使った方が転送の効率はいいので何を使うかは case by case だし、sitecopy でイクと決まっているのであれば別に ssh を使わずに ssl 経由の WebDAV でもいいです。鍵認証はできなくなるけど。 

春がきたっぽい

花粉症じゃないのでそういう具合に春を感じることはなくて、いつも季節は光で感じている。春は単純に明るい。北陸の冬も以前よりはるかに晴れ間が多いけど、それでも春はイエローの多い暖かめの光に変わってくることが分かる。1あと、この時期は空の色がなくなる。いわゆる春霞の状態。梅の頃から春を感じる人もいるんだろうけど、やっぱり自分はこの春霞こそ春らしいと思うんだな。なんでだろ。

本当は雪解けと暖かめの光の合わせ技が最も美しい春の訪れなんだけど、なかなかねぇ、平地は雪が積もらなくなっているので。雪が少ないのは楽は楽だけど、なんだか寂しいのも事実。なんというか、「春だっ!」という喜びが薄れてしまって。季節感が薄れるのはやっぱりいやですねぇ。2

兼六園も行きやすくなったし、週末は無料開放に行ってみようかな。

ちなみに、新潟平野の中では季節感は「田んぼの色」で感じる。春先は作り直している濃い土の色、初夏は田植えで一面が鏡のように光を反射し、夏は青緑、晩夏からは黄金色に変わり、稲刈りが終わると刈り取りの跡と土の色が混ざって微妙な中間色を織りなし、冬はスノーホワイト3になる。この変化を匂いで感じる人もいるけど、自分は鼻があまりよくなくて視覚系の人間らしく、昔から色と光で感じていた。

  1. 冬の光はシアンとかブルーとかが入っている。 

  2. 旬の食べ物で感じる季節感つーのもありますが。 

  3. トミオカホワイトでも可。 

げー。できてんじゃん。

lily

blosxom の考え方が気に入ったがスクリプトが気に入らず、おまけにもう Perl は書きたくねーよ、と思っていたところ、さくらという素朴な実装を見つけて、見守ろうかと思ったが、自分でも練習用に書けるかも、などと思っていたのに、もうまともな実装ができちゃったのね。じゃあこっちを見守ろう。

説教講座が激しく改修中なのでこっちにメモ。

池田フェローは GLOCOM へ

光ファイバーに市場原理を @CNET Japan

どうなるのかと気に掛けたフリをしていた池田フェローは GLOCOM に就職できたようだ。しかし今回の話を読んで思ったのは、「オープンソースなんか無理に追わなくても、この手の話の方がよほど得意なのでは?」ということだった。逆に今はこういう話を分かりやすくネットで書ける人材はあまりいないので、池田氏にはこっち方面で頑張ってもらいたいなぁ。

PukiWiki 1.4 テスト開始

まだ localhost でしか動かしてないですが、明らかに 1.4 の方が速いですね。いいかも、これ。あちこち勝手が違ううえにまだ rc2 なので、本家で質問投げまくっておきませう。リリース時には情報が(増え | 整理され)ているかもしれない。

こうなると気になるのは PukiWikiMod の動きですな。

どうやら自己ベスト更新

Orca 350位

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm