STNSの独自サーバーを書いてみた

オンプレサーバーに加え、複数のクラウドサービスや VPS を使うようになってくると Linux サーバーのアカウント管理が非常に面倒になってきました。（全てがコンテナと SaaS になるのはまだ先）

そこで以前から気になっていた [STNS](https://stns.jp/) を試してみることにしました。すべてを VPN で接続しているわけでもなく、IPアドレス制限で頑張るのもクラウドらしくなく LDAP 公開は出来ない。STNS はクライアント証明書も使えるし、ユーザーのパスワードを登録しなければ最悪取られてもアカウント名、uid, gid, 公開鍵程度なので公開しても大丈夫そう。

[STNSサーバー](https://github.com/STNS/STNS) が公開されていますが、サーバーグループごとにログインできる人をコントロールしったかったため独自のサーバーを書くことにしました。STNS は HTTP で https://stns.jp/en/interface に沿った JSON を返せば良いだけなのでサーバーを書くのも難しくありませんでした。

## 作ったプロトタイプサーバー

* 管理 UI としてDjango の Adminapp が便利そうだったので Django に挑戦しました
* ユーザーは複数の公開鍵を持つ
* ユーザーは複数の unix group に所属できる
* ユーザーには有効期限を設定可能
* ユーザーは有効・無効フラグをもつ
* サーバーの識別は Basic 認証のIDまたはクライアント証明書のCommonNameを使う
* サーバーとユーザーがそれぞれ1つ以上のロールを持ち、これでどのユーザーがどのサーバーにログインできるのかを制御する

![stns-server-1.png](https://qiita-image-store.s3.amazonaws.com/0/8739/fb4a3dbc-d9b8-ba57-888f-dfd54c673aeb.png)

## サーバーの起動

CentOS 7 でとりあえず起動

```bash
sudo yum -y install https://centos7.iuscommunity.org/ius-release.rpm
sudo yum -y install git gcc python36u python36u-devel python36u-pip
git clone https://github.com/yteraoka/morion.git
cd morion
git checkout develop
python3.6 -m venv venv
. venv/bin/activate
pip install -r requirements.txt
cd morion
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver 0.0.0.0:8000
```

http://server:8000/admin/ にアクセスして `createsuperuser` で作成したアカウントでログインして各種リソースを作成する。クライアント証明書によるサーバー識別は未実装なので Basic 認証を使う、サーバーリソースにパスワードを設定する。

## CentOS 7 でのクライアントセットアップ

### package のインストール

https://github.com/STNS/libnss_stns

```bash
curl -fsSL https://repo.stns.jp/scripts/yum-repo.sh | sh
sudo yum -y install stns libnss-stns libpam-stns nscd
```

### libnss_stns.conf の編集

```bash
sudoedit /etc/stns/libnss_stns.conf
```

次の内容で package に含まれており、環境に合わせて編集する

```toml
api_end_point = ["http://localhost:1104/v3"]
# user = "basic_user"
# password = "basic_password"
# wrapper_path = "/usr/local/bin/stns-query-wrapper"
# chain_ssh_wrapper = "/usr/libexec/openssh/ssh-ldap-wrapper"
# ssl_verify = true
# request_timeout = 3
# http_proxy = "http://example.com:8080"

# [request_header]
# x-api-key = "token"
```

### ログイン時に Home directory を作成するための設定

```bash
echo 'session required pam_mkhomedir.so skel=/etc/skel/ umask=0022' \
   | sudo bash -c "cat >> /etc/pam.d/sshd"
```

### OpenSSH Server が Public key を STNS サーバーから取得できるようにする

```bash
sudo sed -i -r \
  -e 's@^#?(AuthorizedKeysCommand) .*@\1 /usr/lib/stns/stns-key-wrapper@' \
  -e 's@^#?(AuthorizedKeysCommandUser) .*@\1 root@' \
   /etc/ssh/sshd_config
sudo systemctl restart sshd
```

### nsswitch.conf 設定 (passwd, shadow, group に stns を追加)

```bash
sudoedit /etc/nsswitch.conf
```

```
passwd:     files sss stns
shadow:     files sss stns
group:      files sss stns
```

### nscd.conf 設定 (毎回外部へ問い合わせていては遅いのでキャッシュさせる)

```bash
sudoedit /etc/nscd.conf
sudo systemctl enable nscd
sudo systemctl start nscd
```

(TTL の動作が期待と違ってよくわからん・・・)

### SELinux 対応

SELinux が enforcing だとうまく動かないため、関係するドメインを permissive にする

```bash
sudo yum -y install policycoreutils-python
sudo semanage permissive -a sshd_t
sudo semanage permissive -a chkpwd_t
sudo semanage permissive -a nscd_t
```

## 試してみて

* 便利、使えそう
* 履歴などを残そうとすると Web UI を持たせるよりも TOML や YAML で Git 管理の方が良かった
  * オリジナルの STNS サーバーはコレで TOML ファイル管理
* 更新頻度的にも Web UI は必要じゃなかった
* サーバー書き直して実用したい

## Slide

[![stns-server-slide1.png](https://qiita-image-store.s3.amazonaws.com/0/8739/818f736d-5860-a550-e6e4-886470240e6a.png)](https://www.slideshare.net/yteraoka1/stns)
https://www.slideshare.net/yteraoka1/stns

## 追記

ユーザー（グループ）単位でのアクセス制限については sshd_config の AllowGroups を使うことで解決できるため、これを理由に独自サーバーを実装する必要はなかったと判明しました。