2010/11/29

CouchDB: ApacheをReverse Proxyサーバにしてみた、完成版

ApacheをReverse Proxyにすると、SSL化や認証についてApacheに関する情報がそのまま流用できて便利だよね、と思い認証ハンドラを作成しました。 とりあえず自分が使うのに必要なものを作って、一般化するために最低限の機能だけを加えています。

CouchDB Wikiにある Apache_As_a_Reverse_Proxyの手順でも似たようなことはできますが、null_authentication_handlerを使う事で、localhostのユーザは無制限にadmin権限を手に入れることができてしまいます。

これはReverse Proxy ServerとCouchDBを別のサーバで動かす場合に、気をつけなければならない点です。

この認証ハンドラは強固なセキュリティを提供するものではありませんが、いくらかリスクを軽減する事ができるはずです。

最終的に仕上げたCouchDB 1.0.1用のパッチは、新しいハンドラを追加しただけで、既存の機能は変更していないので、内部的な変更がなければ基本的には他のバージョンでも動くはずです。

この認証ハンドラは AlexにDebian lennyを入れた環境で試しています。 Erlang-R14BとCouchDB-1.0.1は手動でコンパイルしました。

セットアップ手順

~/20101127.1.couchdb101.webproxy.diffを準備して、CouchDB-1.0.1をコンパイルしたディレクトリに移動します。

$ cd apache-couchdb-1.0.1
$ patch -p1 < ~/20101127.1.couchdb101.webproxy.diff
$ cd src/couchdb
$ make
$ sudo cp couch_httpd_auth.beam /usr/local/lib/couchdb/erlang/lib/couch-1.0.1/ebin/

local.iniなどのiniファイルで認証にwebproxy_authentication_handlerを使用するようにします。

local.iniに追加する設定

[httpd]
authentication_handlers = {couch_httpd_auth, webproxy_authentication_handler}

この認証ハンドラは2つのオプションを取ります。

  • require_authentication_db_entry (default: true) - trueの場合、authentication_dbにユーザ名に対応したエントリがない場合、認証に失敗します
  • webproxy_use_secret (default:false) - trueの場合、Reverse Proxyが適切なX-Auth-CouchDB-Tokenヘッダを付与しない場合、認証に失敗します

これらを加えた一般的なこの認証ハンドラを使う場合の設定は次のようになります。

一般的なlocal.iniファイル

[httpd]
WWW-Authenticate = Basic realm="administrator"
authentication_handlers = {couch_httpd_auth, webproxy_authentication_handler}

[couch_httpd_auth]
require_valid_user = true
require_authentication_db_entry = true
webproxy_use_secret = false
secret = 329435e5e66be809a656af105f42401e

Reverse Proxy側の設定 (Apache)

Debianでは/etc/apache2/sites-enabledディレクトリに置いた設定ファイルをhttpdが認識します。 まずは/etc/apache2/sites-enabledにファイルを作成します。

Port 80用設定ファイル: /etc/apache2/sites-available/couch

<VirtualHost couch.example.org:80>
	ServerAdmin webmaster@example.org
	DocumentRoot /var/www/
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
	CustomLog /var/log/apache2/access.log combined
<IfModule mod_alias.c>
        Redirect permanent / https://couch.example.org/
</IfModule>
</VirtualHost>

Port 443用設定ファイル: /etc/apache2/sites-available/couch-ssl

<IfModule mod_ssl.c>
<VirtualHost couch.example.org:443>
	ServerAdmin webmaster@example.org
	DocumentRoot /var/www/
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
	CustomLog /var/log/apache2/ssl_access.log combined
	SSLEngine on
	SSLCertificateFile    /etc/ssl/certs/ssl-cert-couch.pem
	SSLCertificateKeyFile /etc/ssl/private/ssl-key-couch.pem
	BrowserMatch ".*MSIE.*" \
		nokeepalive ssl-unclean-shutdown \
		downgrade-1.0 force-response-1.0
        <Location />
           AuthType Digest
           AuthName "CouchDB"
           AuthDigestDomain /
           AuthDigestProvider file
           AuthUserFile /etc/apache2/htdigest.db
           Require valid-user
        </Location>
        <IfModule mod_proxy.c>
           ProxyPass / http://127.0.0.1:5984/
           ProxyPassReverse / http://127.0.0.1:5984/
        </IfModule>
</VirtualHost>
</IfModule>

サーバ名やファイル名など、具体的には次の内容が適切か確認してください。

  • VirtualHost couch.example.org:80
  • Redirect permanent / https://couch.example.org/
  • VirtualHost couch.example.org:443
  • SSLCertificateFile /etc/ssl/certs/ssl-cert-couch.pem
  • SSLCertificateKeyFile /etc/ssl/private/ssl-key-couch.pem
  • AuthUserFile /etc/apache2/htdigest.db

ファイル名を指定して、a2ensiteコマンドで設定を有効にします。

$ sudo a2ensite couch
$ sudo a2ensite couch-ssl
$ sudo /etc/init.d/apache2 restart

CouchDB側の設定

設定自体は冒頭に説明しましたが、その内容について解説します。

require_authentication_db_entryについて

trueの場合、authenticate_db(default: '_users')にユーザ名(example: username)に対応する文書(example: /_users/org.couchdb.user:username)がない場合、認証に失敗します。

require_authentication_db_entryを"false"にすると対応する文書がなくてもアクセス可能となります。 その場合は文書があればroleが設定され、なければroleは空"[]"になります。

webproxy_use_secretについて

trueの場合、HTTP Request Headerに適切なX-Auth-CouchDB-Token行がない場合、認証に失敗します。

変更したIfModule mod_proxy.cの内容

<IfModule mod_proxy.c>
        <IfModule mod_headers.c>
            RequestHeader add X-Auth-CouchDB-Token "c21ec459f6a650dcf6907f2b52e611a069a7aeee"
        </IfModule>
        ProxyPass / http://127.0.0.1:5984/
        ProxyPassReverse / http://127.0.0.1:5984/
</IfModule>

X-Auth-CouchDB-Tokenに指定する値はSHA1のHMACで、計算方法は 以前に投稿したように、salt = 329435e5e66be809a656af105f42401eとして次の手順で行ないます。

$ erl -pa /usr/local/lib/couchdb/erlang/lib/couch-1.0.1/ebin
1> nl(couch_util).
2> nl(crypto).
3> crypto:start().
4> Secret = <<"329435e5e66be809a656af105f42401e">>.
5> couch_util:to_hex(crypto:sha_mac(Secret,Secret)).
"c21ec459f6a650dcf6907f2b52e611a069a7aeee"

webproxy_use_secretがデフォルトのままfalseの場合、ローカルユーザがdummyのAuthorization行を追加した場合に、認証に成功してしまいます。

$ curl -H 'Authorization: Digest username="admin"' http://localhost:5984/_session

セキュリティの観点から設定をお勧めしますが、設定が少し難しいので、デフォルトの値をfalseとしています。

CouchDBは使えるのが基本ですからね。

couchdbをリスタートして設定を反映させます。

$ sudo /etc/init.d/couchdb restart

稼働確認

SSLに自己認証CA局を使っている場合は、そのcacert.pemファイルを指定して他のホストから次のようなリクエストを投げてみます。

$ curl --digest --cacert cacert.pem -u admin:xxxxxx https://couch.example.org/_session

0 件のコメント: