Linuxユーザーと公開鍵を統合管理するサーバ&クライアントのSTNSを書き直した

この度、Linuxユーザーと公開鍵を統合管理するサーバ&クライアントのSTNSをすべて書き直し、v2をリリースしたので、お知らせします。

v1リリース時の記事は下記にあります。

はじめに

STNS v2のリリースに当たり、改めてLinuxの名前解決について紹介します。
Linuxはファイルのパーミッションやログイン権限の管理にユーザー名やグループ名が使われています。しかし、実際にパーミッションに利用されている値はID値であり、それらを名前と紐付けるためにいわゆる名前解決が必要です。

$ id example
uid=2000(example) gid=2000(example) groups=2000(example)

この例ですと、exampleユーザーはID 2000を持つユーザーであることがわかります。

これらの名前解決を行うにあたり、Linux標準の仕組みですとuseraddコマンドでユーザーを追加すると、通常は/etc/passwd/etc/group/etc/shadowファイルにユーザーやグループの情報が書き込まれるのですが、昨今、デザイナーによるデプロイのためのログインなど多くの職種がサーバにアクセスする機会が増えており、それらを手で管理したり、プロビジョニングツールで管理するのはあまりベターな仕組みとは言えません。また人材の流動性も上がっており、入退職もしやすくなったため、ワンストップでユーザー管理ができる必要があります。

このようなユーザー管理を行うにあたり、ある程度サービス規模が大きくなってくるとLDAPやDBを利用してユーザー管理を行うのが常であったと思いますが、LDAPやDBでの管理はWeb業界で好まれるコード管理やGitHub WorkFlowと必ずしも相性がよくありません。

それらを解決するために、筆者が開発したのがSimple Toml Name Serviceです。

v2のアーキテクチャはこちらの図のとおりです。

STNSを利用すると下記のようなシンプルな設定ファイルでユーザー・グループの統合管理を行うことができます。


[users.pyama]
id = 1001
group_id = 1001
directory = "/home/pyama"
shell = "/bin/bash"
keys = ["ssh xxxxxxx"]

[groups.pyama]
id = 1001
users = ["pyama"]

筆者の所属するGMOペパボでは、この設定ファイルをThorスクリプトを利用して、GitHubAPIから自動で生成し、ユーザー・グループ管理を行っています。この運用の便利なところはGitHub上のチームとサーバのアクセス権が一致させやすいことや、GitHubには公開鍵情報があり、そのまま利用できること、GitHubの情報をもとにしているので権限の剥奪漏れが少ないことです。

一方でファイル生成の方法はユースケースによって異なると思うので、この記事ではインストールから名前解決までを解説し、v2の変更点を紹介したいと思います。

各種ドキュメントは下記のサイトをご確認ください。

サーバのインストール

Rhel系、Debian系ともにパッケージを提供しています。この手順はUbuntu xenialで進めます。まずクライアントからのクエリに応答するサーバをインストールします。まずはパッケージリポジトリを追加します。


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

リポジトリをインストールしたらサーバをインストールします。


$ apt install -qqy stns-v2

次に設定ファイルを編集し、このようにしてみました。

$ cat /etc/stns/server/stns.conf
[users.example]
id = 1001
group_id = 1001
keys = ["ssh-rsa XXXXX…"]

[groups.example]
id = 1001
users = ["example"]

設定を編集したらrestartしてください。


$ service stns restart

curlを利用して動作確認しましょう。

$ curl -s http://localhost:1104/v1/users | jq
[
  {
    "id": 1001,
    "name": "example",
    "password": "",
    "group_id": 1001,
    "directory": "",
    "shell": "",
    "gecos": "",
    "keys": [
      "ssh-rsa XXXXX…"
    ]
  }
]

たったこれだけでサーバの構築は完了です。次にクライアントをインストールします。

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

クライアントもサーバと同じくパッケージからインストール可能です。


$ apt install -qqy libnss-stns-v2

サーバと同じように設定ファイルを書きます。

$ cat /etc/stns/client/stns.conf
api_endpoint     = "http://localhost:1104/v1/"

STNS自体の設定はこれで完了です。次に nsswitch.conf を下記のように編集し、Linuxの名前解決にSTNSを利用するようにします。下記のように passwd, group,shadowstnsを追加してください。

$ grep -e passwd -e shadow -e group /etc/nsswitch.conf
passwd:         compat stns
group:          compat stns
shadow:         compat stns

ここまでの作業でSTNSで名前解決ができるようになります。

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

STNSを利用してSSHログインする

STNSはLinuxのユーザー、グループの名前解決だけではなく、SSHの公開鍵ログインもサポートしています。公開鍵ログインを行うには、 /etc/ssh/sshd_config に下記の設定を行います。

PubkeyAuthentication yes
AuthorizedKeysCommand /usr/lib/stns/stns-key-wrapper
AuthorizedKeysCommandUser root

次にsshdをrestartします。

$ service ssh restart

テストするために公開鍵をSTNSに設定します。

$ mkdir /home/example && chown example /home/example
$ su - example
example@localhost:~$ ssh-keygen
...
example@localhost:~$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkokLd+sFWbKuqepOVNhStZA55MYQ+RiXiS9Ub1PhS5aPDh06MHf80oLg9mKoG883ZsjD7zgYKunUnafG3NdFqHHTgMLS3By0IPi3ZNKVZStvjvCEahqoAs7gUEzOuNqa9hW9f7f5BfausSSuJ1s00WglrPmCMLvfBf9Y54o3xZm+/Uw8ehFHi8s1x5p/7I25WlEwbkL24CmugvvKuWh/bIcK84xRJO43m2Q/u3IArQjOum8Xim+Psj1xDc6DkbToHmoVCnFDoyMUM+VjnLPYpE4gh/8DBFlzNnRi4FrahJMJGbG/wGP6uovbcbmoj46/nYXGMlzBvU3WnhZbOskf/ example@localhost

$ cat /etc/stns/server/stns.conf
[users.example]
id = 1001
group_id = 1001
# ★作成した公開鍵を設定する
keys = ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkokLd+sFWbKuqepOVNhStZA55MYQ+RiXiS9Ub1PhS5aPDh06MHf80oLg9mKoG883ZsjD7zgYKunUnafG3NdFqHHTgMLS3By0IPi3ZNKVZStvjvCEahqoAs7gUEzOuNqa9hW9f7f5BfausSSuJ1s00WglrPmCMLvfBf9Y54o3xZm+/Uw8ehFHi8s1x5p/7I25WlEwbkL24CmugvvKuWh/bIcK84xRJO43m2Q/u3IArQjOum8Xim+Psj1xDc6DkbToHmoVCnFDoyMUM+VjnLPYpE4gh/8DBFlzNnRi4FrahJMJGbG/wGP6uovbcbmoj46/nYXGMlzBvU3WnhZbOskf/"]

[groups.example]
id = 1001
users = ["example"]

$ service stns restart

ここまででsshログインが可能になるので試してみます。

$ ssh localhost -l example
Last login: Sun Sep  9 02:11:43 2018 from ::1
example@localhost:~$

無事ログインできましたね。このように比較的少ない手番でLinuxの統合ユーザー管理が可能になるので、中小規模でお困りの方がいたらぜひ利用してみてください。またサーバサイドは普通のHTTPサーバなのでnginxやkeepalivedと組み合わせて冗長化することも可能ですし、Basic認証やToken認証に対応しているのでHTTPS化してセキュアな運用も可能です。

さて次にv1からの変更点をいくつか紹介します。

v1からの変更点

nscdが不要

従来のv1ではSTNS自体にキャッシュ機構がなかったため、nscdを利用したキャッシュが必要だったのですが、v2からは独自のキャッシュ機構が組み込まれているためnscdなしで高速動作が可能です。

インターフェースがRESTfulに

v1ではmapのようなデータ構造であったのですが、Arrayデータ構造へ変更し、よりサーバ側の開発が行いやすくなりました。またエンドポイントも全て見直しています。

before

{
  "pyama": {
    "id": 1001,
    "group_id": 1001,
    "directory": "/home/pyama",
    "shell": "/bin/bash",
    "gecos": "",
    "keys": [
      "ssh-rsa xxxx"
    ]
  }
}

afterr

[{
  "name": "pyama",
  "id": 1001,
  "group_id": 1001,
  "directory": "/home/pyama",
  "shell": "/bin/bash",
  "gecos": "",
  "keys": [
    "ssh-rsa xxxx"
  ]
}]

libnss-stnsがGolangからC言語へ

v1では全てGolangで開発されて追ったのですがv2からはクライアントサイドはC言語で開発されています。理由としてはv1はCGOを利用してクライアントサイドの処理を行っていたのですが、clone時のメモリの持ち回り方などが怪しく、SEGVの要因になっていたので、C言語で書き直しています。

コードの見通しが良くなった

もともとSTNSは筆者が2年ほど前にGolangの学習用途で開発したプロダクトだったのでどちらかというとバッドノウハウの塊のようなコードになっていました。それらを今の力ですべて書き直したので以前よりだいぶ見通しが良くなっています。

パラメーター項目の変更

  • api_end_point → api_endpoint

区切り文字の位置の変更及び、データが配列から、文字列へと変更されています。["http://xxxx"] → “http://xxxx”

v1からの移行パス

サーバ側はVirtualHostなりポートを変えるなりで起動すれば良さそうです。クライアント側は下記のように削除してから、インストールしてください。

$ apt remove libnss-stns
$ apt install libnss-stns-v2

最後に

公開から2年ほど経過し、GitHub Starは180を超え、商用サービスからお声がかかるほど成長した反面、コードベースがあまり良くなくメンテナンスするモチベーションが低くなっていtので、C言語の勉強を兼ねてフルスクラッチで書き直しました。サーバサイドもlabstack/echoを採用し、ミドルウェアを利用した拡張を行いやすくしています。

今後についてはSlackを利用した2FAや監査の仕組みなど機能拡張を進めていく予定です。まだ利用されてない方は利用していただいて、既に利用中の方はv2への移行を進めていただければ幸いです。