2014-06-05: セキュリティ、環境変数、そして
5/20 頃に 公開した envchain というツールの紹介記事を、会社の技術ブログに書いた。
OS X キーチェーンから環境変数をセットするツールを作りました - クックパッド開発者ブログ
投下時間の関係もあると思うけど、思いの他結構拡散してびっくりした。まあ、それは置いておいて、本題。
おもしろい。が、ps -Eで他プロセスで環境変数が見えることを考えると、そもそも環境変数に認証情報を入れてる時点で… / “OS X キーチェーンから環境変数をセットするツールを作りました - クックパッド開発者ブログ” http://t.co/n1quG3C4Tx
— Kazuho Oku (@kazuho) June 4, 2014
ごもっともだと思います。
実際のところ、わたしはなんか「環境変数やめろ bot かよ」と言われるレベルであまり環境変数に機密情報を入れる事を好んでないです。
なのにこのツールをつくってしまった訳だけど… というわけで、kazuho さんとかには断片的にいろいろリプライしたけど自分の見解を個人の日記で述べておきます。
環境変数のセキュリティについて
まずは環境変数のセキュリティについておさらい。
ps -E
, ps -e
について。Linux では /proc/<pid>/environ
でプロセスの環境変数を覗くことができるように, BSD 系では ps コマンドで覗く事ができます。
Linux では environ ファイルは実行ユーザーでないと見れない (少なくとも無関係なユーザー・グループからは見れない) のである程度は安全です。
しかし、 昔の BSD 系 UNIX マシンでは、ps e でコマンドライン引数同様、他人のプロセスについている環境変数を覗く事が可能でした。明確な時期は調べていないのですが、最近の BSD、すくなくとも OS X Mavericks, FreeBSD 1, NetBSD 2 では一般ユーザーから他ユーザーのプロセスは見えなくなっているようです。というわけで、一旦他ユーザーに露出するから危険という指摘は置いておきます。
同じ実効ユーザーを利用しての攻撃リスク
そもそも kazuho さんの指摘においては、「これが keychain を利用しているのは、自分の権限で実行する特定のプログラムに情報を付与するため」 と書かれています。つまり、他ユーザーに覗かれる危険ではなく、自ユーザーで動いているプロセスに対するリスクを懸念しているわけですね。
これは環境変数に機密情報を入れて利用する上で、Linux でも BSD 系でも起こる一つのリスクだと考えられます。 実際覗かれたら終わります。だけれど、クライアントマシンにおいてそんなリスクがあるのかなあと思うと、結構判断がむずかしいです。
また、結局プロセス実行中は復号された状態でメモリ上に存在してしまうわけだけど、まず、envchain が対象としてるのってクライアントマシンなわけだよ。わたしはすくなくともクライアントマシンのユーザーが圧倒的だろうと思ってます。
で、クライアントマシンでのユースケースって、CLI ツールでちょっと小さい処理させてそのプロセスはすぐに死ぬ訳ですよ。わりとすぐ揮発するのでタイミング攻撃になっちゃうわけですね。
突き詰めていくとこんな感じです:
まー他プロセスから見えなくなったところで、メモリ上からどうやって安全に消すのかって問題もあるし、必要になるまでメモリに載せとかなきゃいけないって筋の悪さもあるし、環境変数に認証情報いれるのが良いアプローチでないのは確かなんだろうなー
— Kazuho Oku (@kazuho) June 4, 2014
トレードオフ -- どこで妥協するか
セキュリティはだいたいの場合利便性とのトレードオフなんだよね。
まず、理想形として: 環境変数は使うべきではない。機密情報をセキュアに渡すには fd か tty 経由! とかそういうのに (3) なっちゃいますね。
一方で一番危険なのはコマンドライン引数で、他ユーザーに露出します。 MySQL 5.6 でも -p
にパスワード渡すのダメとか言われるようになったでしょ。
次にマシで楽なのは環境変数でしょうか。今は他人から見えないと思っても問題ないでしょうし。という事で採用されてるんじゃないかなあと思ってます (kazuho さんも 同様の見解)
(余談だけど、openssl コマンドはいくつかの方法でパスワード・パスフレーズを受け付けます。ユースケースに応じて最適な方法を選択しましょう。 openssl(1) "PASS PHRASE ARGUMENTS" )
これらの選択肢のなかからどこで落ち着くかという話。ユースケースに合わせて最適で、気軽に取り組める物が良いと思ったりします。銀行とかだったら面倒でも限りなくセキュアにすべき、みたいな感じですね。リスクと相談しましょう。
envchain の場合
envchain の開発動機は、AWS 系ツールが AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
という二つの環境変数が de facto になっていて、だいたい受け付けてくれる。なので、それをセットして利用する事が多いです。
だけれど、常に指定するのはちょっと危ないよね (詳細は紹介記事参照) というもの。
かといって設定ファイルだとツール毎に設定しないといけなくて煩わしい! 環境変数がいい! でもできるだけセキュアにしたい!
そこで出来たのが envchain なのです。必要な時に必要なプロセスにだけ、暗号化されたストレージから復号してセットする。利便性とリスクの妥協点ですね。
設定ファイルとかに plain text で記述しておくより安全かなと思います。plain text であっても同じユーザーであってファイル位置が特定できてしまえば奪取は容易なわけだし。
envchain もまあコマンド名と namespace 名が特定できれば奪えるわけだけど、Keychain Access とか envchain --set --require-passphrase
で ACL いじっておけば読もうとした時にユーザーへプロンプトされるので安全にしようと思えばできます。
Twelve-factor app
ちょっと話を逸らしますが言及しておこうとおもう。
twelve-factor app とは application のポータビリティとか、スケールのしやすさとか、新規開発者がすぐ取り組めるようにとか、その辺を高めるためにこうしましょう、みたいな事が書いてある。
その中の III. Config 章では設定についてどうすべきかが書かれている。引用するとこんな感じ
Apps sometimes store config as constants in the code. This is a violation of twelve-factor, which requires strict separation of config from code. Config varies substantially across deploys, code does not.
(筆者抄訳) apps はコード中に設定を書く事がまれにあります。これは設定をコードから独立させるべきという twelve-factor に違反します。コードは変わらなくても動作のための設定・環境だけが変わる事があるのです。
なるほどなるほど。まあ yaml とかいろいろ面倒な事考えるより、プラットフォーム側はただひとつ「環境変数」に対応しとけばいろんな設定に対応できるよね。わかるわかる。
いやでもこれ…他ユーザーから読めない時代とは言え…うーん… 悩ましい。利便性は分かる。ある程度安全だし、まあいいのかもしれない。
しかししかし、Ruby には dotenv っていう .env
とかいうファイルから key=value
形式で値を読んで環境変数にセットするライブラリがあるのだけど、これは最高にダメだと思う。ENV
にモンキーパッチで改造してるなら、わざわざプロセスの環境変数として露出させる必要ないじゃん。ENV にパッチあてるなら、透過的にデフォルト値として .env ファイルの中身を利用するようにするとかさぁ。ねぇ?
まとめ
セキュリティ、やっぱりどこで落とし所をつけるかという話になる。今回の事例とユースケースの場合、この程度でリスクは下げられるだろうって考えから環境変数を利用、データソースは暗号化されたストレージ、という所。
はー、セキュリティってむずかしいですね。
以上、環境変数やめろ bot のポエムでした。