STNS」カテゴリーアーカイブ

Linuxのユーザー管理基盤ミドルウェアのSTNSで公開鍵認証を実装できるライブラリを公開しました

STNSとは

ざっくりSTNSを利用するとこれまでLDAPなどで管理されてきたLinuxのユーザーをTOMLフォーマットの設定ファイルやDynamoDB、S3で管理できるようになります。またSSHログインの公開鍵認証などをかんたんに実現できるのがSTNSの優位性でした。

libstns-go

今回そのSTNSを利用して、下記のライブラリを活用するとあらゆるWEBサービスやCLIツールで公開鍵認証が可能になります。

サンプルコードとしては下記のようなものになります。

package main

import (
	"fmt"

	"github.com/STNS/libstns-go/libstns"
	"github.com/k0kubun/pp"
)

func main() {
	stns, err := libstns.NewSTNS("https://stns.lolipop.io/v1/", nil)
	if err != nil {
		panic(err)
	}

	user, err := stns.GetUserByName("pyama")
	if err != nil {
		panic(err)
	}
	pp.Println(user)
        // id_rsaキーで署名する
	signature, err := stns.Sign([]byte("secret test"))
	if err != nil {
		panic(err)
	}

	// pyamaの公開鍵で署名検証できた
	fmt.Println(stns.VerifyWithUser("pyama", []byte("secret test"), signature))

	// 文字列が異なるので署名検証できない
	fmt.Println(stns.VerifyWithUser("pyama", []byte("make error"), signature))

}

実装としては任意の値を ~/.ssh/id_rsa などの秘密鍵で署名し、その署名をSTNSで公開されている公開鍵で検証し、検証成功すればそれはSTNSに登録されたユーザーであると認証することができます。

勘の良い方は気づいたかと思いますが、SSHのログイン時に利用されている公開鍵認証相当のことをあらゆるシステムで可能にしたというのが今回の実装です。

ユースケース

まず公開鍵認証を利用することで一般的なID/Password認証よりも比較的暗号強度が高い認証を行うことができます。さらには多要素認証の一つとして活用いただくのも良いと思います。

あとは社内で利用するツールを開発するときに、OAuth認証は容易に利用できるので僕も重宝しているのですが、CLIツールから利用するとなると非常に手間がかかります。そういった場合に、この仕組を利用するとCLIで完結するかつ、強力な認証を利用できます。

最後に

今回実装してみて思ったのですが世の中意外とそんなに公開鍵認証って実装されてるものって少ないなぁと思ったりもしました。今回の実装の追加でSTNSを利用したおもしろ隙間ソフトウェアとかもできるようになると思うので、是非活用いただいて、ブログなど書いていただけると大変に嬉しく思います。

ちょっとかんたんに試してみたいのだけど!という方がいらっしゃいましたら、STNS as a Serviceもあるのでお試しください。

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への移行を進めていただければ幸いです。

SSHのログイン先でも最適化されたvimが使いたい

サーバでオペレーションするときに、ちょっとトラブルシュートしたりするくらいならよいのですが、定期的にログインして作業するサーバがそれなりにあって、その生産性があまり無視できなくなったのでSTNSにstns-setupという機能を設けました。

STNS導入済みのクライアントでstns-setupコマンドを実行すると、事前に定義しておいたコマンドを実行することが出来ます。

$ stns-setup

アトリビュートはこんな感じです。

[users.example]
id = 1000
name = "example"
setup_commands = [
  "git clone https://github.com/pyama86/dotfiles.git /home/example/dotfiles",
  "/bin/sh /home/example/dotfiles/setup.sh"
]

もうアトリビュートを見るだけで何が出来るかお分かりですね?次にみなさんが求める記事を紹介します。

この機能を使えば自分のvimrctmux.confをログイン先のサーバでも簡単にセットアップすることが出来るので、使えたらラッキーくらいな感じで登録しておくと良いのではないでしょうか?

サーバ、クライアントともに0.3-3から利用可能で、エンドポイントは/v3を利用してください。不明な点やバグ等あれば@pyama86まで!

STNSが単体でのTLS暗号化&クライアント認証に対応しました

先日STNS,libnss-stnsともに0.2.2をリリースしました。主な変更内容は下記のとおりです。

  1. TLS暗号化に対応
  2. TLSを利用したクライアント認証に対応
  3. retry_requestパラメーターでクライントのリトライ回数を指定可能にした
  4. ubuntu14.04における再起動が完了しない不具合を修正

TLS関連

これまではnginxなどと組み合わせてTLS/SSL暗号化を提供していましたが、@naoto_gohkoさんからissueを頂いたのと、昨今みんな出来るだけサーバ立てたくないんだろうなぁというフォースを感じたので、単体でTLS暗号化に対応し、サーバ、クライアント共にパラメータを追加しています。
STNS.jp Configuration

tls_ca   = "keys/ca.pem"      # using only client authentication
tls_cert = "keys/server.crt"
tls_key  = "keys/server.key"

クライアント、サーバいずれもパラメーターの内容は一緒ですが、サーバのtls_ca及び、クライアントのTLS関連のパラメーターについてはクライアント認証を行うときだけ指定してください。

TLS暗号化だけを利用する場合

  • stns.conf
tls_cert = "keys/server.crt"
tls_key  = "keys/server.key"
  • libnss_stns.conf
api_end_point = ["https://example.jp:1104/v2"]

TLSクライアント認証を利用する場合

  • stns.conf
tls_ca   = "keys/ca.pem"
tls_cert = "keys/server.crt"
tls_key  = "keys/server.key"
  • libnss_stns.conf
api_end_point = ["https://example.jp:1104/v2"]
tls_ca   = "keys/ca.pem"
tls_cert = "keys/client.crt"
tls_key  = "keys/client.key"

クライアント認証を利用することでベーシック認証よりも堅牢になるので、グローバルな環境でより安心してSTNSを運用することが可能になります。

retry_requestパラメーターの追加

minneの踏み台サーバにログインできなくなった〜」という声を@hsbtさんから頂いたので調べてみると、STNSサーバに何らかの理由で疎通できなかったときに、nscdがネガティブキャッシュしてしまい、名前解決ができなくなっていました。NWの状況等に応じてはそれなりに起きることなので、クライアント側でリクエストをリトライできるようにしています。request_timeoutと合わせて利用することにより、問い合わせのミスを減らせると思うのでご活用ください。

ubuntu14.04における再起動が完了しない不具合を修正

@manabusakaiさんからフィードバックを頂いて、調査したところ、OS起動時にdbus-daemonが起動した際に、libnss-stnsがロードされて、コマンド実行を行う場合、またOS起動時にinitramfsで起動し、/usr/local/binなどが見えていない状態のときにコマンドを実行しようとすると、プロセスの起動、停止などが正常に動作しない状態になる不具合がありました。
straceで追いかけるとlibc.soに対してdbus-sendが失敗する挙動であったため、OS起動時にlibnss-stnsに対して、動的呼び出しが行われたとしても、以降の処理を行わず無視することで収束しています。普段自分が運用していないOSでの利用実績や、そのフィードバックを頂けて本当に助かりました。

実は本件、原因がわからず、30時間位ハマっていたのですが、I have matsumotoryなので、相談したら5分くらいでヒント情報もらえたのでホント便利。

その他

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-22-22-54-23

先日Qiitaに投稿されたLinuxユーザ管理の決定版? 〜STNSとサーバレスで夢が広がる〜【cloudpack大阪ブログ】の記事がバズっており、嬉しすぎてその日は3人位に缶コーヒーを奢ってしまいました。STNSを活用いただき、ただただ感謝です!こういった事例をみてhttp://stns.jpのドキュメントも拡充しておりますので、どんどんハックしてもらえれば幸いです。