仙石浩明の日記

2006年4月14日

DB サーバのセキュリティ向上策 (6)

DB サーバのセキュリティ向上策 (3)」では、 どのユーザが UNIX ドメインソケットにアクセスしたか特定するために、 ユーザごとにソケットを作成しました。 しかし Linux などの OS では、UNIX ドメインソケットに限り アクセス元のユーザを getsockopt(2) で調べることができるので、 ソケット一つだけでどのユーザからのアクセスか区別することができます。

例えば以下のように getsockopt の引数に SO_PEERCRED を指定することにより、 ucred 構造体にアクセス元のユーザの情報が格納されます:

struct ucred cr;
int len = sizeof(cr);
int ret = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (ret == 0) {
    struct passwd *passwd = getpwuid(cr.uid);

    ...

}

したがって、UNIX ドメインソケットを listen し、 そのソケットへ接続があったら、 それを DB サーバへ通信を監視しつつ中継するプログラム dbrelay において、 上記のように getsockopt(2) を使ってアクセス元ユーザを特定し、 通信の監視によって得られた DB ユーザ名と一致したら中継を継続し、 一致しなかったら通信を遮断する、ということが可能になります。

もちろん、各ユーザが直接 DB サーバへアクセスしないよう、 dbrelay からのアクセス以外は OUTPUT チェインで通信を却下します。

このような仕掛けを、ラック内の全サーバに仕込むことにより、 各ユーザは同名の DB ユーザでのみ DB サーバへ、 UNIX ドメインソケット経由でアクセスできます。

通信の監視をクライアント側でなく、 DB サーバ側で行ないたい場合は、 クライアント側の dbrelay では アクセス元のユーザ名をサーバ側へ伝えるだけにして、 通信の監視および通信の遮断はサーバ側で行なわせることもできます。

最新版 の stone には アクセス元のユーザ名をサーバ側へ伝える機能があるので、 例えばクライアント側で次のように stone を実行します。

stone dbserver:12345/http /tmp/db.sock '\U'

「/http」の指定と「'\U'」が、ユーザ名をサーバ (dbserver:12345) へ 伝える設定です。例えばユーザ sengoku が UNIX ドメインソケット /tmp/db.sock にアクセスすると、stone はまず

Apr 14 07:54:36.809789 16384 3 5>6 73 65 6e 67 6f 6b 75 0d  sengoku.
Apr 14 07:54:36.809828 16384 3 5>6 0a 0d 0a                 ...

を dbserver:12345 へ送信し、その後は /tmp/db.sock から dbserver:12345 への 中継が行なわれます。 したがってサーバ側ではまず最初に送られてきたユーザ名を受け取り、 その後は通信を監視しつつ 12345 番ポートから DB サーバへの中継を行なえばよいわけです。

Filed under: stone 開発日記,システム構築・運用 — hiroaki_sengoku @ 08:13

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment