自宅サーバー構築譚：SSH 公開鍵認証・公開鍵を集中管理

# 能書き

[自宅サーバー構築譚：基本構想](https://qiita.com/katz_engineer/items/cb592be44daa28a51d9b)に基づく自宅サーバー構築、[Ubuntu22.04LTSインストールその2](https://qiita.com/katz_engineer/items/033471b69143bf76650e)の続きです。[Hyper-Vに構築したクライアントマシンもどき](https://qiita.com/katz_engineer/items/bf9299e8f9afd19975e8)も使用します。

OpenLDAP をインストールし、利用環境を整えています。その4回目、最終回です。

# 目標

[OpenLDAP 関連作業初回](https://qiita.com/katz_engineer/items/0e2c299f943a7b13e2c4)に掲げた作業の題目を再掲します。

1. [LDAPインストール。そしてログを rsyslog に出力する設定。](https://qiita.com/katz_engineer/items/0e2c299f943a7b13e2c4) ←完了
1. [LDAP over TLS を設定。そしてサーバーマシンとは別のクライアントマシンから ldaps アクセス。](https://qiita.com/katz_engineer/items/c7445176881900120d03) ←完了
1. [クライアントマシンに sssd をインストールしてログイン。LDAP でのアカウント管理を実現。](https://qiita.com/katz_engineer/items/693ab241fc6aa8452b0d) ←完了
1. SSH の公開鍵接続。公開鍵の LDAP 管理を実現。クライアントマシンから SSH 接続。 **←イマココ**

という訳で今回は、SSH を公開鍵接続する設定とし、その公開鍵を LDAP に登録、接続時に参照させようとしたんですが。見事に撃沈されました。

このネタ、考えていたより難しい。CentOS なら記事も沢山あるんですが Ubuntu では皆無。一番難しいのは LDAP に新しいスキーマを追加する点。どうしても方法がわかりません。諦めました……

そこで今回は予定を変更してお送りします。調査の過程で目に付いた、公開鍵を```$HOME/.ssh```に保管するのではなく一ファイルに格納して集中管理する方式を試みます。

ssh 公開鍵を一箇所で集中管理できるのは魅力的です。家庭向けの小規模なサーバー管理では、実現できたからなんだと言う訳ではありませんがね。折角調べた知識が埋もれてしまうのもナンですし、やってみます。

# 参考文献

- [OpenSSH で全ユーザの公開鍵を1ファイルで管理する - meta's blog - The Power To Serve](https://w.vmeta.jp/tdiary/20170829.html)
- [LDAPSEARCH - ユーザコマンド(セクション1) - OpenLDAP 2.3 MAN ページ](http://www5f.biglobe.ne.jp/~inachi/openldap/man23/man1/ldapsearch.1.html)
- [OpenLDAP - SSH公開鍵を登録してログインするまでの手順 - Qiita](https://qiita.com/makaaso-tech/items/d9353b7e3128966d607f)
- [LDAPによるSSH公開鍵認証を行いたい - teratail](https://teratail.com/questions/283183)
- [2017年版 SSH公開鍵認証で使用する秘密鍵ペアの作り方 - Qiita](https://qiita.com/wnoguchi/items/a72a042bb8159c35d056)

# サーバーの準備

## スナップショット

[スナップショットだいじ。超だいじ。](https://qiita.com/katz_engineer/items/f3bd2f7af2ba49db156c#%E3%82%B9%E3%83%8A%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)

今回もスナップショット対象が少し異なるので注意。

```console:サーバー
sudo zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_ssh_authkey
sudo zfs snapshot tank/ROOT/ubuntu/usr/local@$(date +%Y%m%d_%H%M%S)_before_ssh_authkey
```

## SSH サーバー設定

公開鍵の置き場所を決めます。公開される鍵ですし、どこでも良いんですが。今回は```/opt/ssh/publickeys.list```としました。

```console:サーバー
sudo mkdir /opt/ssh
sudo touch /opt/ssh/publickeys.list
```

```publickeys.list```の中身はタブ区切りのテキストファイルとします。下記2つの項目をタブ文字で区切って1行とします。
1. ユーザー名
1. 公開鍵

sshd が公開鍵を取得する為のシェルスクリプトを作成します。これは自作しました。

```console:サーバー
sudo mkdir /opt/ssh/bin
cat <<"___" | sudo tee /opt/ssh/bin/ssh_authorized_key.sh >/dev/null
#!/bin/bash
look -t $'\t' $1$'\t' /opt/ssh/publickeys.list | cut -f2
___
sudo chmod +x /opt/ssh/bin/ssh_authorized_key.sh
```

そして Linux の伝統に則り```/usr/local/bin```にシンボリックリンクを張ります。

```console:サーバー
sudo ln -s /opt/ssh/bin/ssh_authorized_key.sh /usr/local/bin/ssh_authorized_key.sh
```
シェルスクリプト実行専用のユーザーアカウントが必要との事。

```console:サーバー
sudo useradd -s /usr/sbin/nologin -M sshauthkey
```

設定ファイルを調整して、作成したシェルスクリプトを呼び出すようにします。
同時にパスワード認証を禁止しときます。

```console:サーバー
cat <<___ | sudo tee /etc/ssh/sshd_config.d/ssh_authorized_key.conf >/dev/null
AuthorizedKeysCommand /usr/local/bin/ssh_authorized_key.sh
AuthorizedKeysCommandUser sshauthkey
AuthorizedKeysFile none
PasswordAuthentication no
___
```

sshd を再起動します。

```console:サーバー
sudo systemctl restart sshd
```

# SSH 接続用の鍵

ここからは、クライアントマシンとサーバーマシンの操作が少し入り組んできます。

## 秘密鍵と公開鍵を生成

接続するユーザーとしてログインして、SSH 接続の為の鍵を生成します。ユーザー名は taro とします。暗号の種類は、昨今の情勢を鑑みて楕円曲線暗号 Ed25519 にします。

なお```ssh-keygen```コマンドは Windows も持っています。このコマンドは Windows でも、コマンドプロンプトでそのまま実行できます。良い時代になりましたな。

```console:クライアント
ssh-keygen -t ed25519 -P ""
```

鍵ペアは```$HOME/.ssh```ディレクトリに作成されて、それに関して問合せがありますので、何も入力せずに Enter キーを押しましょう。

```console:クライアント
$ ssh-keygen -t ed25519 -P ""
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/taro/.ssh/id_ed25519):
Created directory '/home/taro/.ssh'.
Your identification has been saved in /home/taro/.ssh/id_ed25519
Your public key has been saved in /home/taro/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:yg7Rh9ME/T4oNlVnGmlJv1/2hKFxO5rLHi9V4qljXmQ taro@yuki
The key's randomart image is:
+--[ED25519 256]--+
|      .. ..o     |
|       .. *.o    |
|        .+ =o o  |
|     . +. o  =.+.|
|    . +.So  o.E++|
|     o++. o  *+=.|
|    ..oo   .+oo .|
|     o     .==   |
|      .    +=o.  |
+----[SHA256]-----+
```

## 公開鍵をサーバーへ送付

[以前確立した手順](https://qiita.com/katz_engineer/items/8c0dcbb985d4493200d2)でもって、公開鍵をサーバーへ送付します。
サーバー名は secondary.home とし、ユーザー名は taro とします。

```sftp```コマンドも Windows は持っています。残念ながら```cd```コマンドはオプションが違うので、そこは適当に調整して下さい。

```console:クライアント
cd ~/.ssh
```

```console:クライアント
sftp publickey@secondary.home
```

```console:クライアント sftp
cd publickey
mkdir taro
cd taro
put id_ed25519.pub
exit
```

## サーバーで公開鍵一覧表に追加

送付された公開鍵をサーバー側で受け取ります。具体的には、公開鍵一覧表に追加してから並べ替えます。

```console:サーバー
KEYOWNER=taro
cat <(echo -n $KEYOWNER$'\t') /srv/publickey/publickey/$KEYOWNER/id_ed25519.pub | sudo tee -a /opt/ssh/publickeys.list >/dev/null
sudo sort -u /opt/ssh/publickeys.list -o /tmp/publickeys.list
sudo mv /tmp/publickeys.list /opt/ssh/publickeys.list
```

処理が済んだ印として、サーバー側の責任で公開鍵を削除しておきましょう。

```console:サーバー
sudo rm /srv/publickey/publickey/$KEYOWNER/id_ed25519.pub
sudo rmdir /srv/publickey/publickey/$KEYOWNER
```

# 動作確認

動作を確認します。ssh 接続時にパスワード入力要求が無ければ成功です。

```console:クライアント
ssh taro@secondary.home
```

# 仕舞い

上手くいったら```/etc```を Subversion コミットしておきます。
まずは今回の差分を確認。

```console:サーバー
sudo svn st /etc
```

今回はユーザー追加などもあったので、下記のようになりました。

```console:サーバー
$ sudo svn st /etc
M       /etc/group
M       /etc/gshadow
M       /etc/passwd
M       /etc/shadow
?       /etc/ssh/sshd_config.d/ssh_authorized_key.conf
M       /etc/subgid
M       /etc/subuid
```

問題無いようなのでコミットします。

```console:サーバー
sudo svn st /etc | grep "^?" | cut -b9- | xargs -I{} sudo find {} -type f -or -type d -or -type l | xargs -t sudo svn add
sudo svn ci /etc -m"ssh: public key authentication, prohibit password"
```

これで、パスワード認証ではなくて公開鍵認証方式で ssh 接続できるようになりました。
しかも鍵は一箇所で集中管理です。出来れば LDAP で管理したかったのですが、それはまた今度という事で。
ともあれ、ひとまず作業が纏まりました。やったね:thumbsup_tone1: