Linuxユーザーと公開鍵を統合管理するサーバ&クライアントを書いた[更新]

皆様、明けましておめでとうございます。
ホリデープロジェクトでgoを用いたサーバ&クライアントSimple Toml Name Serviceを書きました。
このサーバ&クライアントを導入するとLinuxサーバのSSHの公開鍵認証に利用する鍵とユーザー、グループをtoml設定ファイルで管理できるようになります。

はじめに

ご存知の通りLinuxはユーザー名とユーザーIDを保持しており、各々の値から双方を解決出来る仕組みがあります。


$ id pyama uid=1001(pyama) gid=1001(pyama) groups=1001(pyama)

この場合、ユーザー名はpyama、ユーザーIDは1001です。実際にはid pyamaコマンドを実行すると、ユーザー名pyamaを元に、ユーザーIDやグループ名、グループIDが取得されています。通常この値は/etc/passwdに書くか(user add foo)、LDAPなどの外部サービスで管理することが多いと思います。

しかし、昨今はサーバインフラのクラウド化、DevOps文化によるアプリケーションエンジニアのインフラ進出により、以前よりもより多くのサーバ、ユーザーを管理する必要が生まれています。その中でchefなどを用いたプロビジョニングでのユーザー管理や、LDAPでのユーザー管理が煩雑になってきており、それをもっとシンプルに出来ないかという思いで、開発に至りました。シンプルにするために下記の設計思想を反映しています。

1.多くをやらずに一つをやる
2. シンプルなインターフェースを実装し、組み合わせを可能とする

できるようになること

  • SSH接続に利用する公開鍵、ユーザー情報をtoml設定ファイルで管理できるようになる
  • シンプルなインターフェースを用いて色々なミドルウェアと組み合わせることが出来る

インストール

追記:最新のインストール手順はこちらをご確認下さい。

システムの構成はリクエストに対して、jsonでレスポンスを返すstnsとOSからの呼び出しを元にstnsにリクエストを投げるlibnss_stns.soをはじめとするクライアントで構成されています。このインターフェースで公開鍵、ユーザー情報を取得することが出来ます。

stns.001

早速CentOSにインストールしてみましょう。


・サーバのインストール

リポジトリを利用してインストールが可能です。
GitHubのREADMEをご確認ください。


$ curl -fsSL https://repo.stns.jp/scripts/yum-repo.sh | sh $ yum install stns

設定ファイルは/etc/stns/stns.confに配置されます。pyamaユーザーを作成してみます。


# port = 1104 # include = "/etc/stns/conf.d/*" [users.pyama] id = 1001 group_id = 1001 directory = "/home/pyama" shell = "/bin/bash" keys = ["ssh xxxxxxx"] [groups.pyama] id = 1001 users = ["pyama"]

設定ファイルを編集した場合はreloadもしくはrestartを実行してください。reloadはシステム無停止で設定ファイルを読み込み直しま
す。


# service stns restart Reloading stns configuration (via systemctl): [ OK ]

stns-query-wrapperを使用して動作を確認します。


$ /usr/local/bin/stns-query-wrapper /user/name/pyama { "pyama": { "id": 1001, "group_id": 1001, "directory": "/home/pyama", "shell": "/bin/bash", "gecos": "", "keys": [ "ssh-rsa xxxx" ] } }

以上でサーバの構築は完了です。設定ファイルの分割に対応しているので、組織グループごとに分割などの利用方法も可能です。


クライアントのインストール

まず最初に、名前解決のキャッシュを行うnscdをインストールし、キャッシュを可能にします。


$ yum -y install nscd

この例でははpasswdとgroupをキャッシュするように設定しています。

        enable-cache            passwd          yes
        positive-time-to-live   passwd          600
        negative-time-to-live   passwd          300
        check-files             passwd          yes
        shared                  group           yes

        enable-cache            group           yes
        positive-time-to-live   group           3600
        negative-time-to-live   group           300
        check-files             group           yes
        shared                  group           yes

        enable-cache            hosts           no
        enable-cache            services        no
        enable-cache            netgroup        no

設定が完了したら忘れずにrestartしておきましょう。


$ service nscd restart

続いてクライアントをインストールします。
サーバと同じくリポジトリを公開しています。


$ curl -fsSL https://repo.stns.jp/scripts/yum-repo.sh | sh $ yum install libnss-stns

設定ファイルは/etc/stns/libnss_stns.confに配置されます。こちらは問い合わせ先のサーバのエンドポイントを指定してください。


api_end_point = "http://<server_ip>:1104"

続いて名前解決にstnsを利用するために、/etc/nsswitch.confを編集します。


passwd: files stns shadow: files stns group: files stns

上記のようにfilesの後ろにstnsを書いてあげてください。こうしておくと/etc/passwd,/etc/shadow,/etc/groupで対象のレコードがない場合に、stnsに問い合わせが行われます。ここまで設定するとpyamaユーザーの情報が取得できるようになります。


$ id pyama uid=1001(pyama) gid=1001(pyama) groups=1001(pyama)

もしこのタイミングで確認できない場合、ネガティブキャッシュしている可能性があるので、nscdをrestartしてください。

続いてSSH公開鍵認証に用いる鍵をstns-key-wrapperを利用して取得する設定を/etc/ssh/sshd_configに設定します。


PubkeyAuthentication yes AuthorizedKeysCommand /usr/local/bin/stns-key-wrapper AuthorizedKeysCommandUser root

こちらも同じく設定後にsshdをrestartしてください。


$ service sshd restart Redirecting to /bin/systemctl restart sshd.service

また下記をpamの設定に追加することによって、SSHログイン時にホームディレクトリを自動で作成してくれます。


echo 'session required pam_mkhomedir.so skel=/etc/skel/ umask=0022' >> /etc/pam.d/sshd

ここまでの設定で無事SSHログインが可能となります。


$ ssh 192.168.70.11 -l pyama Last login: Mon Jan 11 15:39:32 2016 from 192.168.70.1 [pyama@client ~]$

sudoを利用するならば、この例ですとgroupをpyamaとしているので、sudoersに下記のエントリを追加すればsudoが可能となります。


# suコマンドは抑制する Cmnd_Alias NOTSU = /bin/su %pyama ALL=(ALL) NOPASSWD: ALL,!NOTSU

以上で一通りの導入が可能となります。おそらくコード化せずにオペレーションしても5分もかからずにインストールすることが出来ると思います。


性能面

手元のMacBook AirのVagrantで立てたsntsのab結果です。(Core:2 Memory:512MB)

$ ab -c 100 -n 100000 http://172.16.0.14:11104/user/name/pyama
Server Software:
Server Hostname:        172.16.0.14
Server Port:            11104

Document Path:          /user/name/pyama
Document Length:        605 bytes

Concurrency Level:      100
Time taken for tests:   14.626 seconds
Complete requests:      100000
Failed requests:        0
Write errors:           0
Total transferred:      75700000 bytes
HTML transferred:       60500000 bytes
Requests per second:    6837.32 [#/sec] (mean)
Time per request:       14.626 [ms] (mean)
Time per request:       0.146 [ms] (mean, across all concurrent requests)
Transfer rate:          5054.54 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.9      1       9
Processing:     0   13   7.6     12     182
Waiting:        0   12   7.5     11     180
Total:          0   15   7.5     14     184

Vagrant上でコア1、メモリ1Gのマシンでabを実行し、keepalive無しでRequests per second: 6837.32なので十分実用に耐えうるのではないかと思います。
keepalivedを入れると10149.22rps程度までは処理が可能です。

最後に

導入が非常に容易であることに加え、実装はシンプルなjsonサーバ、クライアントです。例えばサーバ側をtomlではなくMySQLとRailsで実装したとしてもインターフェースさえ合わせておけば問題なく動作します。

対してクライアントもlibpam-mrubyなどからstnsのAPIを呼び出して利用するといったことも容易に可能です。そして、nginxと組み合わせてSSL対応、認証対応することも出来ますし、keepalivedと組み合わせて冗長を取ることも可能です。

こういった拡張性が高い理由は多くをやらず一つをやるという思想のもとに構築されているからです。SSH公開鍵認証のためだけにLDAPに疲弊している方、試してみてはいかがでしょうか?
意見は要望は@pyama86にお願いします。