Ansibleのtemplateにカスタムフィルタを追加

Ansibleのtemplateモジュールではjinja2が使われているため、カスタムフィルタを登録して好きな処理を書ける。

templateはplaybookのパース時にも使われるので、Ansibleロード時点でグローバルなプラグインとして導入する必要がある。今のところロードするフィルタの切り替えはansible.cfgで切り替えるしか無いようだ。 (ドキュメントには ./libraryに置くことでロードできるらしいのだがcfgで上書きされているっぽい)

フィルタの登録はFilterModule().filters()が返す辞書。

import socket
class FilterModule(object):
    def filters(self):
        return {"A": socket.gethostbyname}

このファイルを適当な名前でfilter_pluginsフォルダに置くとansibleロード中に読み込まれる。

実際のパス指定はansible.cfgの

filter_plugins     = /usr/share/ansible_plugins/filter_plugins

参照: https://github.com/ansible/ansible-examples/blob/master/language_features/filter_plugins/custom_plugins.py

Serversman@VPSをx86_64に初期化してみた

DTIのServersmanVPSをx86_64で初期化しなおしたら色々パラメータが変更されたようなのでメモ。

大雑把に約1年間centos-i386ゲストシステムをリブート無しに運用していたためか、vCPUも変化していた。

ip6tables

x86_64システムで初期化したためipv6tblesが使えるようになった。ただしカーネルが古く-m stateなどを使えない。--synは使えるようなのでステートレスながら一応フィルタしておく。

もっともDTIはまともにiptablesのモジュールをロードしてくれないので使えるだけまし。 iptablesはOSテンプレートのiptables関連パッケージが古すぎてそのままでは機能しない。yum upgradeして初めて使える様になった。

cpuinfo

100MHz8スレッドから400MHz2に変更された。シングルスレッド性能が低すぎたので要望が多かったのかもしれない。

model name      : Intel(R) Xeon(R) CPU           L5630  @ 2.13GHz

beancounter

以前のログを残すのを忘れていたので変更点は不明なものの、sock/rcvbuf周りがリミットに引っかかっている。 Basicプランの保証メモリが1Gに増えたといえ、他のリソース制限が厳しくやはり使い切ることは難しそう。

Version: 2.5
       uid  resource                     held              maxheld              barrier                limit              failcnt
    53658:  kmemsize                  9240107             19584032             35565240             36830248                    0
            lockedpages                     0                   20                  256                  256                    0
            privvmpages                158277               319242               524288               557056                    0
            shmpages                     3841                 7057                65536                65536                    2
            numproc                        49                  101                  240                  240                    0
            physpages                   64306                97889                    0  9223372036854775807                    0
            vmguarpages                     0                    0               262144               262144                    0
            oomguarpages                64322                97889                26112  9223372036854775807                    0
            numtcpsock                     23                   71                  360                  360                    0
            numflock                        3                   16                  188                  206                    0
            numpty                          2                    5                    8                    8                    0
            numsiginfo                      0                    6                  128                  128                    0
            tcpsndbuf                  190496               624000              1720320              2703360                    0
            tcprcvbuf                  205640              1721224              1720320              2703360                  111
            othersockbuf                48888              1122152              1126080              2097152                 1069
            dgramrcvbuf                     0               262048               262144               262144                24596
            numothersock                   45                  269                  360                  360                    0
            dcachesize                 391703               595466              6819840              7249920                    0
            numfile                      1383                 2290                 9312                 9312                    0
            numiptent                      47                   47                  256                  256                    0

Robots.txtチェッカーを作ってみた

http://forbiddenrobots.usb0.net/

Googlerobots.txtとmetaタグ仕様 https://developers.google.com/webmasters/control-crawl-index/docs/robots_txt に準じているつもり。

Flask+uwsgi-emperor+MongoEngineを試すのがメインだったので、 コアはFlask、サーバーはnginx+uwsgiでuwsgi-emperorでプロセス管理、バックエンドにMemcachedキャッシュとMongoEngine。 httpにpython-requests、htmlパーサはBeautifulSoup4という普通な構成。

ひとまず動くところまで出来たけれど、gevent化やmongodbの分散とか実装してみたい。 いまだにgeventをwindows環境で動かすことができていないのでしばらく掛かりそうだけど。

CentOS6+NginxでECDHEを有効にしてForward Secrecy取得までのメモ

昨日は鍵共有を甘く見て爆死したためCentOS+NginxのサーバーをWindows環境に対応させてみる。

RPMに慣れていた都合上、主なサーバーにCentOS6を使っている。 CentOS/RHEL6.4では2013年10月時点で、標準のOpenSSLは1.0.0、Nginxは1.0系が導入される。Nginxには公式リポジトリもあるが、openssl-1.0.0を前提にビルドされている。

これらはコミュニティサポートのあるRPMで提供されているものの、NginxでHTTPSサーバーを建てようとすると、TLSはv1.0 まで、対応cipherはDHE-RSA-AES-SHAまでになり、QualsysのSSLテストでは色々と指摘される。

問題点

既存のパッケージで対策不能なのは、TLS1.2対応(兼BEAST対策)とRSA鍵共有。

BEASTは未対策のブラウザがTLSv1.0以前のCBCモードで通信する場合に発生しうる。一時的な対策としてストリーム暗号のRC4が使われているが、TLSv1.2ではCBCモードの問題が解消されているためTLSv1.2で導入された暗号モードを使えば問題は無い。しかし、TLSv1.2はopenssl-1.0.0には入っていない。

将来解読される可能性がある(RSA)鍵共有を使わない、というForward Secrecyは各所で既に行われている。RSA鍵共有に替わるものとして、多くのブラウザはDH鍵共有・ECDH鍵共有が実装されている。 CentOSのopensslでも有効なDH鍵共有を利用できればいいのだが、クライアント側、例えばWindows+IE環境ではDHE-RSAが無いためにRSA鍵共有が優先され、Forward Secrecyを保証できないことをご指摘頂いた。(Win7+IEでブラウザのCipherテストみるとDHE-DSSは実装されているのにDHE-RSAが無い)

Windows+IEに対応するためには、ECDH鍵共有を有効にする必要がある。Googleなど多くのサービスは既にECDHE-RSAを有効にしている。

ビルド手順

TLSv1.2と、多くのブラウザでRSA鍵共有以外を使おうとすると、OpenSSLとNginxをリビルドする必要があった。

システムのopensslをいじるのでVMなどのビルド用サンドボックス環境で要検証。

まず、1.0.1のopenssl-develをビルド環境にインストールする。 CentOS6でのopenssl-1.0.1e のビルド手順は http://www.ptudor.net/linux/openssl/ がとても詳しいのでそのまま。 生成されたRPMをインストールしてopenssl version が1.0.1eになり、openssl cipher -v 'HIGH' でKx=ECDHが含まれるかチェックしておく。

Nginxはmainline 1.5.6のSRPMをリビルド。自動インストールするのであれば、nginx.specファイルでRequires: openssl >= 1.0.1e のバージョンを指定しておく。 出来たバイナリはopenssl-1.0.1eのcipherに対応しているはず。 例えば

  ssl_protocol TLSv1.2;
  ssl_ecdh_curve secp384r1;
  ssl_ciphers EECDH+aRSA+AESGCM;

が通るか確認。

実際のciphers指定

次のように明示しておく。

    ssl on;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    # RC4無し
    ssl_ciphers EECDH+HIGH:EDH+HIGH:HIGH:+3DES:!RC4:!MD5:!aNULL:!eNULL:!LOW:!EXP:!PSK:!SRP:!DSS:!KRB5;
    # RC4有り
    # ssl_ciphers EECDH+AESGCM:EECDH+SHA384:EECDH+SHA256:EECDH+RC4:EECDH+HIGH:EDH+AESGCM:EDH+SHA384:EDH+SHA256:EDH+RC4:EDH+HIGH:AESGCM:SHA384:SHA256:RC4:HIGH:+3DES:!MD5:!aNULL:!eNULL:!LOW:!EXP:!PSK:!SRP:!DSS:!KRB5;
    ssl_ecdh_curve prime256v1;
    ssl_dhparam /path/to/dhparam2048.pem;
    ssl_certificate /path/to/server.crt
    ssl_certificate_key /path/to/private.key
  • ECDHE>DHE>RSAを明示する。OpenSSLのデフォルトのソートは、ソート順がEnc→KxなのでKxが交互に並んでしまう。
  • 将来証明書がRSAからECDSAに切り替わった時のために、grep Au=RSAgrep Au=ECDSAで順序が変わらように並べる。
  • GCM>SHA-2>RC4SHA-1なのは、SHA-2未対応のクライアントはTLSv1.0である可能性があり、BEAST対策なされていないかもしれないから。
  • MD5はSSL3.0ならSHA-1必須なので抜く。
  • RC4をそのまま抜くとWinXP+IEで接続できなくなるので、cipherの最後に+3DESを追加する。
  • EC関数のsecp384r1は互換性から減点される模様
  • ECDHは256bit以上、DHは2048bit以上が推奨されている。Nginxのデフォルトは1.5.6でもDH1024bitのままだった。
  • !aNULL以降は表示されるcipher削減のため。利用するクライアントは存在しないかそれ自体脆弱と考えていい
  • 性能上の問題は無視している。

これでほぼ全てのブラウザで対応できたはず。

Forward Secrecy   Yes (with most browsers)   ROBUST (more info)
続きを読む

SSLとGPGの秘密鍵と鍵交換(訂正)

Lavabitに関するGeekなページの記事をみて、GPG(あるいはS/MIMEなどのメッセージ・データ暗号化)と、SSLの秘密鍵や鍵交換が混同されているようなのでメモ。

(追記)

実際にRSA鍵交換が有効だったようで、通信についても証明証用の秘密鍵から復号できた。

失礼しました。御指摘ありがとうございます。 (/追記)

SSLとGPGの秘密鍵

LavabitのようなWeb上の暗号化システムでは、二つの全く異なる暗号化の仕組みがある(あった)。

SSLでのサーバー証明用秘密鍵

まず、サーバーとユーザーの間はTLS(SSL)で共通鍵による暗号化と、公開鍵暗号による検証が行われる。

ユーザーが本人であることを認証するためには通常パスワード認証を使うが、サーバー認証、すなわちサーバーが本当にLavabitであると保証するためには、サーバー証明書と呼ばれる公開鍵暗号が用いられる。

Lavabitのサーバーは自身が本物であることを示すために、サーバー証明書に対応する秘密の暗号鍵、いわゆるSSL秘密鍵を保持している。ユーザーはサーバーから送られたメッセージが証明書に記載された復号鍵で正しく復号できるか検証する。

この秘密鍵が盗まれると、Lavabitのふりをした偽のサーバーを作ることが出来てしまう。サーバー証明書の秘密鍵を押収することで、それ以降に送受信されるメール内容を奪うことはできるが、FBIが興味を持つであろう過去の暗号化されたメールについてはサーバ証明書の秘密鍵があっても意味は無い。

SSLにおける鍵交換

証明書と対応する署名用の秘密鍵と、TLSセッションの暗号化のための共通鍵暗号(AESなど)とは異なる。共通鍵はTLS接続の都度、DH鍵共有などで安全に生成され、(一定時間キャッシュされることはあるが)接続が終われば破棄される。そのため共通鍵はサーバーにもユーザーにも残らない。安全な鍵共有アルゴリズムを利用していれば、通信を中継するルーターなどにも残ることはない。

TLSではDH方式などの安全な鍵共有は基本的に必須(なければブラウザが警告する)なので、LavabitがTLS/SSLにおいてDH鍵共有をしていなかったという事は考えにくい。

(追記) DH鍵交換が無効化されていて、RSA鍵交換が優先される状態だった模様。RSA鍵交換では署名用のRSA公開鍵を流用して、クライアントが指定した鍵を公開鍵で暗号化してサーバーが復号する。そのため、FBIが通信を傍受していた期間に交された通信は解読され得る。

RSA鍵共有では、サーバーのデータを閲覧し、その後サーバーから削除していたとしても通信記録に全てが残ってしまうため、現在ではRSA鍵交換は使うべきではなく、互換性のために残されている(と思っていた) (/追記)

GPG暗号の復号用秘密鍵

GnuPGが基盤とする公開鍵暗号では、送信者が「受信者の公開された暗号鍵」で暗号化し、受信者はメールボックスに届いたメールを「受信者の秘密の復号鍵」で解読する。 メールではなくデータの暗号化であれば、書き込み時に(公開してもよい)暗号鍵で暗号化、読み出し時に秘密の復号鍵を用いる、と言い換える事ができる。いずれにせよ、秘密鍵を持っているユーザーだけが、メッセージを復号出来る。

Lavabitではこの暗号処理をサーバー上で行ない、ユーザーのメールデータを公開鍵で暗号化して保管していたようだ。例えばメール受信用のSMTPサーバーは暗号化してデータベースに保存するだけで、コピーや復号鍵を持つ必要は無い。

ただし、LavabitはWebメールサービスなので、秘密鍵がサーバーに存在しなければデータを復号して表示出来ない。つまりユーザーの秘密鍵もまたLavabit側に保存されていたことになる。 本来メッセージの復号処理はユーザーの所有する端末上で行うべきだが、Lavabitではサーバー側が秘密鍵を管理して復号処理をも代行することで、GnuPGなどを導入できない端末でも利用できた。

このサーバーに置かれた鍵が、FBIが欲しがるユーザーの過去のメールデータを復号するための秘密鍵にあたる。

ユーザーが復号用の秘密鍵を自分のPCで管理していれば、FBIは利用者全員のPCを一つ一つ押収する必要があったのだが、Lavabitサーバーに秘密鍵管理を任せていたために、FBIは全員分のメールと秘密鍵を一度に押収出来てしまった。

GPG署名での鍵交換

鍵交換を使うことでより安全になるという部分は、メール内容のGPG署名の上で、更に鍵交換を適用するべき、という意味と思われる。

GPG暗号の用いる暗号基盤では長期間同じ秘密鍵を使い続けることを前提としているため、一度秘密鍵が盗まれると、対応する公開鍵で暗号化した過去の受信メールが全て復号されてしまう。 Lavabitでいえば、わずかな秘密鍵のリストで全てのデータを復号される事になった。

そこで、長期間使い続ける秘密鍵は署名と鍵交換にだけ利用し、メール内容の暗号化には通信の都度(あるいは一定期間毎に)新しい鍵を生成・交換して暗号化を行う、という方法がある。

たとえば、最初のメールに自身のGPG署名付きの新しい公開鍵を返信先として指定してメールし、秘密にしたい内容はその返信に添付された公開鍵を使って送る、というような場合。

長期的に使う本来の秘密鍵を破棄するわけにはいかないが、使い捨ての鍵であれば、メールを再度読む必要が無くなったら秘密鍵を破棄できる。 つまり、GPG署名の上でさらに鍵交換を利用すると、傍受したメールを復号するために、すぐに削除されてしまう一時的な鍵を盗み出しておかなければならなくなり、過去のメールを復号することが困難になる。

たとえ全てのメールが中継サーバーで傍受されていて、自分の現在の復号用秘密鍵が押収されたとしても、一時的な鍵が削除されていればメールは復元することが出来ない。TLSのクライアント認証や、SSHによるクライアント・サーバー認証はこれを自動的に行なっている。

ただしLavabitの件に習うと、こういった秘密鍵を破棄する手法は、それ自体証拠隠滅と見なされるかもしれない。

Exim4はSMTP-AUTH over TLSをサポートしない

exim4の実装は、他のSMTPサーバーにSMTP-AUTHでログインする際に、TLSのCommon Nameではなく逆引きドメイン名に対応する認証情報を送ってしまう。

本来フル機能のMTAのexim4が、二つ以上の異なるスマートホストに対する認証情報を持つ、というレアなケースでは、あるホストが他のホストに送られるべき認証情報を詐取することが出来る。

実際には複数のスマートホストを設定することは稀だろうから、現実にこの問題が脅威となることは考えにくい。単一の(あるいは同じ管理者が運用する)SMTP-AUTHサーバーに依存しているのであれば、サーバーの逆引き名が変化しても、そのSMTP-AUTHアカウントが使えなくなるだけだ。

ただし、eximが保持するパスワードがTLSで正しく保護されていないのは事実で、検証されたドメインをまたぐ情報漏洩を許す実装は潜在的に脆弱であると見るべきだ。 万一、exim4に複数のアカウントのパスワードを持たせている場合には、一つを残して他を削除することが望ましい。

SSL/TLSが保証するのは「接続先が、証明書の持ち主である」ということだけ。TLS接続を確立できても、証明書と無関係なドメインの情報を送信してしまうのでは意味が無い。

攻撃シナリオ

eximがそれ自体では直接メールを送信せず、リモートの二つのスマートホスト(フル機能のMTA) somehost.example.comotherhost.example.netTLS接続で利用している。 設定時には、DNSレコードが

somehost.example.com.  A  10.1.2.3
otherhost.example.net  A  10.4.5.6

とその逆引きだったとする。

Debianのドキュメントにならえば、パスワードが書かれる/etc/exim/passwd.clientは次のようになる。

somehost.example.com:someuser:somepasswd
otherhost.example.net:otheruser:otherpasswd

設定した時点では、二つのサーバーはそれぞれ固有の証明書を持っているので、証明書を検証することで、目的のホストに正しく接続したことを保証できる。

ここで、

  • otherhostが乗っ取られたが、まだ証明書は失効していない
  • DNSインジェクションなどで経路を操作可能

という条件がそろうと、otherhostを掌握した攻撃者はeximが持つ、somehost用の認証情報を盗むことが出来る。

例えば、次のようにな毒入れをして、otherhostを経由するメールが来るのを待つ。

otherhost.example.net.  CNAME  somehost.example.com.
6.5.4.10.in-addr.arpa.  PTR somehost.example.com.
somehost.example.com.   A 10.4.5.6    ; inject it

eximはTLS接続先のCommonNameではなく、逆引きしたドメイン名を用いてSMTP-AUTHサーバーを識別するので、otherhost.example.net に正しくTLS接続し、パラノイアチェックしているにも関わらず、somehost.example.comの認証情報が送信される。 そしてSMTP-AUTHは通常(TLSで保護されるので)平文パスワードが用いられる。

Intel HD Graphicsの59p病の対処法

59p病とは、モニタのリフレッシュレートが何故か60p(60Hz プログレッシブ)にできず、59pに固定されてしまう症状[要出典] 。

自分のIvy系列のHD Graphics+UXGAモニタで発病していた。60p Hzを選択出来るが、適用すると59pに戻ってしまう場合。 長らく解消方法が無いと思っていたが、解決方法が見つかったのでメモ。

  1. グラフィックプロパティからインテルグラフィックコントロールパネルを開く。
  2. 詳細設定モードに変更
  3. カスタム解像度パネルで、カスタム解像度として使用中の解像度と60pを指定して作成 例えば、 1920x1200 60Hz 32bitで生成
  4. 解像度を上書きするか尋ねられるので上書きする。このタイミングで解像度が一旦 800x600に落とされた。
  5. 作成した解像度を選択すると、リフレッシュレート設定に失敗するらしく、一旦黒画面、15秒待って元の解像度に回復するのを待つ
  6. カスタム解像度パネルから作成した解像度を削除する
  7. 一般設定から、目的の60pに設定できるようになる

すごくドライバのバグっぽい。IntelはもうちょっとUXに関わる部分の実装にも力入れるべきだと思う。

なお環境は以下のとおり。最新版のグラフィックドライバ入れたらデスクトップに凄まじい描写遅延が生じて使い物にならなかったのでマザーボードベンダーの提供する古いバージョン。

Driver Version:           9.17.10.2884
Operating System:       Windows 7  Service Pack 1(6.1.7601)
Default Language:       Japanese (Japan)
DirectX* Version:       11.0
Physical Memory:        16055 MB
Processor:          Intel64 Family 6 Model 58 Stepping 9
Processor Speed:        2600 MHz
Vendor ID:          8086
Device ID:          0152
Device Revision:        09
Monitor Name:         汎用 PnP モニター
Display Type:           Digital
Gamma Value:            2.2
DDC2 Protocol:          Supported

Maximum Image Size:
Horizontal:         18.50 inches
Vertical:           11.81 inches

Monitor Supported Modes:
640 by 480 (60 Hz)
800 by 600 (60 Hz)
800 by 600 (56 Hz)
1024 by 768 (60 Hz)
1280 by 960 (60 Hz)
1280 by 1024 (60 Hz)
1440 by 900 (60 Hz)
1600 by 1200 (60 Hz)
1680 by 1050 (60 Hz)
1920 by 1200 (60 Hz)