分散ユーザー管理システム「etcdpasswd」の紹介

こんにちは、アプリ基盤チーム兼Necoプロジェクト所属の @ueokande です。 本日はNecoで開発しているUNIXユーザーの管理ツールである「etcdpasswd」を紹介します。

github.com

etcdpasswdは、etcdをバックエンドに持つ分散型のユーザー管理システムです。 etcdpasswdは自律型の分散システムで、一時的にホストがダウンしても、次回起動時にetcdのユーザーを参照して同期します。 etcdpasswdはLDAPのようなNSS (Name Service Switch) が外部サービスに問い合わせるのではなく、etcdpasswdが各ホストにある /etc/passwd を更新します。

なぜetcdpasswdなのか

現在のcybozu.comデータセンターでは、各ホストのユーザー追加・更新は、MySQLでユーザー管理されており、管理者が適用したタイミングで各ホストに同期されます。 この方式はシンプルですが、スクリプトを実行した瞬間にホストがダウンしていた場合に、そのホストの更新が漏れてしまうという課題がありました。

forest user management architecture

etcdpasswdは、etcdをバックエンドに持つ分散型のユーザー管理システムです。 ユーザー情報はetcd上に記録されます。 etcdpasswdでは ep-agent と呼ばれるエージェントプログラムを各ホストにインストールします。 ep-agent はetcd上の変更を監視して、変更点をローカルに反映します。 これで、仮に対象ホストが一時的にダウンしてたとしても、次回復帰時に ep-agent が起動すれば最新のユーザー情報が適用されます。 ep-agent の起動は、通常systemdなどを設定しておけば、OS起動時に自動で起動するはずです。

etcdpasswd architecture

Necoではデータンターのブートサーバー上のユーザー同期に、etcdpasswdを利用しています。 ブートサーバーは、データセンターの初期構築や、踏み台が利用できなくなったときなどの緊急時に利用しています。 初期構築や緊急時などLDAPのようなNSSが使えない環境でも、etcdpasswdは利用できます。 またNSSとは違いローカルの /etc/passwd にユーザー情報を書き込むので、バックエンドのetcdに接続しなくてもログイン可能です。 たとえばバックエンドのetcdがクラスタ崩壊して接続できなくなったとしても、ユーザーはブートサーバーに無事ログインできます。

etcdpasswdの使い方

ep-agentはユーザーを同期する各ホストにインストールします。 ep-agentを実行すると、バックエンドのetcdを監視して、変更があれば各ノードにデプロイした ep-agent がローカルのユーザー情報を追加・更新します。

$ cat /etc/etcdpasswd.yml
endpoints: [ "https://10.20.30.1:2379", "https://10.20.30.2:2379", "https://10.20.30.3:2379" ]
tls-cert-file: /etc/etcdpasswd/tls-client.crt
tls-key-file: /etc/etcdpasswd/tls-client.key

$ sudo ep-agent
2018-09-28T04:17:27.883450Z boot-1 ep-agent info: "start sync" rev=1
2018-09-28T04:17:27.884434Z boot-1 ep-agent info: "finish sync" rev=1

管理者用のCLIツール etcdpasswd はetcdに接続して、etcd上に記録されてるユーザー情報を更新します。 まずetcdpasswdを利用する前に、いくつか初期設定を適用します。

# UID/GIDの開始番号
$ etcdpasswd set start-uid 2000
$ etcdpasswd set start-gid 2000

# デフォルトグループとデフォルトの追加グループ
$ etcdpasswd set default-group wonderland
$ etcdpasswd set default-groups sudo,adm

ユーザーの操作は etcdpasswd user サブコマンドで利用できます。 またetcdpasswdはSSHの公開鍵の埋め込みにも対応しており、etcdpasswd cert サブコマンドで利用できます。 登録された公開鍵は ep-agent が各ユーザーのホームディレクトリ以下の .ssh/authorized_keys に配置します。

# グループ追加
$ etcdpasswd group add wonderland

# ユーザー追加
$ etcdpasswd user add mad-hatter
$ etcdpasswd user add march-hare

# SSH鍵の追加
$ etcdpasswd cert add march-hare id_rsa.pub

以上で登録したSSH公開鍵に対応する秘密鍵を使って、 ep-agent が動いているホストにログインできます。

また管理外のユーザーのパスワード認証を無効化する機能があります。 ブートサーバーの初期設定の時のみ、インストール時に作成したユーザーでパスワード認証します。 初期設定が終わるとそのユーザーは使わないので、初期ユーザーのパスワード認証を無効化します。 etcdpasswd locker サブコマンドで、ユーザーのパスワード認証を無効化できます。

# aliceのパスワード認証を無効化
$ etcdpasswd locker add alice

etcdpasswd internal

etcdpasswdの内部を少し案内します。 デーモンプログラム ep-agent および クライアントツール etcdpasswd は共にGoで記述されています。 ep-agentはetcdの状態チェックをポーリングではなく、etcdのWatch APIを利用しています。

Watch APIはイベントベースの非同期の監視用のAPIで、etcd上のキーに対する操作があれば都度通知されます。 Watch APIは非常に高信頼で扱いやすいので、Necoでは多くの場所で利用しています。 etcdはMVCC (Multiversion concurrency control) データベースで、etcd上の全ての変更が履歴として残されて、それぞれにリビジョン番号がついています。 Watch APIでもリビジョン番号を指定でき、以前購読した続きからetcdの変更を監視できるので、重複・欠損なく全てのetcd上のイベントを購読することができます。

ep-agent/etc/passwd を直接編集せず、かわりに useradd コマンドなどを呼び出しています。 Necoで etcdpasswd を実行するブートサーバー上ではUbuntuがインストールされています。 シンプルな実装ですが、実用的な多くのディストリビューションはカバーできます。

まとめ

現在のcybozu.comのインフラは、手順をベースにした「自動化」が主でした。 しかし手順の自動化は不測の状態変更に弱く、その度に人間が対応していました。 Necoでは人が理想の状態を宣言し、それぞれのシステムは「自律化」することを目指しています。 それが安定した分散システムを構築するためにNecoでは必要なことで、そのひとつの成果がetcdpasswdです。

Necoではまだまだ紹介したいアプリケーションがあるのですが、また日を改めて紹介していきたいと思います。