自宅サーバー構築譚：公開鍵の送付専用ユーザーを作成

# 能書き

[自宅サーバー構築譚：基本構想](https://qiita.com/katz_engineer/items/cb592be44daa28a51d9b)に基づく自宅サーバー構築、[Ubuntu22.04LTSインストールその2](https://qiita.com/katz_engineer/items/033471b69143bf76650e)の続きです。

[前回はオレオレ認証局を構築](https://qiita.com/katz_engineer/items/ada7b08e7c0254e39126)しまして、公開鍵（及び秘密鍵）を作成できる環境を作りました。

ここで問題になるのが公開鍵の送付です。

セキュリティを鑑みると、最終的には ssh を公開鍵認証するようにしたいのです。しかしその為には、クライアントマシンで作成した公開鍵をサーバーマシンに送付しなければなりません。

USBメモリで物理的に運搬、でも良いのですが一手間掛かります。折角なので電子的に送付できるようにしてスマートな操作を実現したい。

そこで、公開鍵送付専用のユーザーを作成する事にしました。

調べた結果、sftp なら OpenSSH だけあれば構築できるようです。余計なモジュールのインストールは不要。chroot 設定も可能。操作体系は ftp 準拠なので、変なコマンドを実行されてしまう事もありません。

と言う訳で。その為の設定を実施します。

# 参考文献

- [鍵とパスワードの認証を混合するsshd_configの設定 - treedown’s Report](https://blog.treedown.net/entry/2017/05/08/010000)
- [SSHでちょっとした設定TIPS - treedown’s Report](https://blog.treedown.net/entry/2017/06/08/010000)
- [OpenSSH : SSH ファイル転送 (Ubuntu)](https://www.server-world.info/query?os=Ubuntu_22.04&p=ssh&f=2)
- [OpenSSH : SFTP only + Chroot](https://www.server-world.info/query?os=Ubuntu_22.04&p=ssh&f=5)
- [Linux にログインできないユーザを作成する - てしりこじり](https://tesiri.hateblo.jp/entry/2014/10/23/111441)
- [SCPとSFTPの違い - OS - クラウド・AWSのIT技術者向けブログ SKYARCH BROADCASTING](https://www.skyarch.net/blog/scp%e3%81%a8sftp%e3%81%ae%e9%81%95%e3%81%84/)
- [sshdのmatchでユーザ単位・アドレス単位でchrootをさせるなど、matchに応じて処理方法を変える - 201703 - Blog -  俺的備忘録 ～なんかいろいろ～](https://orebibou.com/ja/home/201703/20170331_001/)

# サーバー設定

## root になる

以下の作業の殆どで root 権限が必要になります。
一々```sudo```してもいいのですが。

```console:サーバー
sudo -i
```

## スナップショット

[スナップショットだいじ。超だいじ。](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:サーバー
zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_publickey
```

## ユーザー追加

ユーザー名は publickey とします。異論もおありと思いますが、共通鍵の運搬専用という事で今回はこれにします。

- ユーザー名は publickey
- ホームディレクトリ無し
- ログイン禁止

上記を踏まえて、下記のコマンドを実行します。ユーザー作成とパスワード設定になります。

```console:サーバー
useradd -s /usr/sbin/nologin -M publickey
passwd publickey
```

## 追加したユーザーの sftp 設定

publickey は共通鍵の送付専用です。その送付対象となる共通鍵ファイルは```/srv/publickey```ディレクトリに置く事とします。異論もおありでしょうけども、私はこう決めました！
と言う訳で皆様それぞれの思想に従って細かい点は調整をお願いします。

下記のコマンドを実行します。

```console:サーバー
mkdir /srv/publickey
chgrp publickey /srv/publickey
cat >/etc/ssh/sshd_config.d/publickey.conf <<___
Match User publickey
  X11Forwarding no
  AllowTcpForwarding no
  PermitTTY no
  PasswordAuthentication yes
  ForceCommand internal-sftp
  ChrootDirectory /srv/publickey
___
```

ssh 設定ファイルを作成したら```sshd```を再起動します。

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

# 確認

## 準備

確認用のファイルとディレクトリを準備します。
どうも接続先ディレクトリは root がオーナーで、root 以外の書き込みが禁止されていないと、接続に失敗するようです。従って書き込み確認用にサブディレクトリを用意しておきます。

```console:サーバー
cd /srv/publickey
echo hello,world >hello.txt
mkdir publickey
chgrp publickey publickey/
chmod g+w publickey/
```

こういう場合は権限に注意して確認します。

```console:サーバー
# ls -l
total 2
-rw-r--r-- 1 root root      12 Feb 25 17:48 hello.txt
drwxrwxr-x 2 root publickey  3 Feb 25 18:03 publickey
```

## 接続と転送

別マシンからサーバーへ publickey ユーザーで ssh 接続します。私は Win10 マシンで実行しました。
下記のように、これは失敗します。

```console:クライアント
>ssh publickey@secondary.home
publickey@secondary.home's password:
PTY allocation request failed on channel 0
This service allows sftp connections only.
Connection to secondary.home closed.
```

実は scp も失敗します。解説記事は見つからなかったのですが、どうも ssh 接続できないと scp も出来ないようです。

```console:クライアント
>scp publickey@secondary.home:/hello.txt .
publickey@secondary.home's password:
protocol error: mtime.sec not present
```

sftp は成功します。

```console:クライアント
>sftp publickey@secondary.home
publickey@secondary.home's password:
Connected to secondary.home.
sftp> pwd
Remote working directory: /
sftp> ls -l
-rw-r--r--    1 root     root           12 Feb 25 08:48 hello.txt
drwxrwxr-x    2 root     1001            2 Feb 25 09:03 publickey
sftp> get hello.txt
Fetching /hello.txt to hello.txt
/hello.txt                                                                            100%   12     0.8KB/s   00:00
sftp> cd publickey
sftp> put hello.txt
Uploading hello.txt to /publickey/hello.txt
hello.txt                                                                             100%   12     0.0KB/s   00:00
sftp> ls -l
-rw-rw-r--    1 1001     1001           12 Feb 25 09:04 hello.txt
sftp> pwd
Remote working directory: /publickey
sftp> exit
```

# 仕舞い

動作確認できたら```/etc```を Subversion 登録しましょう。

```console:サーバー
svn st /etc | grep "^?" | cut -b9- | xargs -I{} find {} -type f -or -type d -or -type l | xargs -t svn add
svn ci /etc -m"set publickey user"
```

これで、サーバーマシンとクライアントマシンの間で公開鍵を送付する手段を確保できました。やったね:thumbsup_tone1: