SSHの公開鍵認証とホームディレクトリの関係(※追記あり)

### まえがきと言う名の余談
とある社内システムの開発の面倒をここ数年見ていたのですが、いわゆる「保守」「運用」的なことをする人がいないもんで、何となく流れで私が面倒を見ることに。

しかし、OSの面倒を見るなんて言うのはずっとWindowsの経験しかなく、Linuxを操作するなんて言うのも殆ど経験なく(※)、ただLinuxに触れること自体は前から興味だけはあり、しかしカクカクシカジカと理由を付けて手を付けてこなかったので、これはいい切っ掛けだと思って勉強がてら触り始めました。

### システムの癖と言う名の余談
この社内システム、当初の立ち上げメンバーが癖がある人(達？)だったようで、設計やOSの設定、MWの選定など、随所にその好みが反映されています。

- OSにプレインストール(という言い方するのか？)されてるPostfixを無効化して、わざわざSendmailをインストールして使用　⇒　社内のSMTPサーバにリレーする機能しか使わないのに…
- DBがOracle　⇒　たかだか一日に数千アクセスしかないようなWebアプリケーションなのに…　⇒　現在は`PostgreSQL`に更改済み
- 何故かアプリケーション実行用ユーザアカウントのホームディレクトリが、`/home`配下ではなく`/var`配下

そしてこの「ホームディレクトリ」が、後々問題になってきたのです。

### システムの構成とバックアップの仕様と言う名の余談
このシステム、構成が以下のようになっています。
OSは全て`RHEL(Red Hat Enterprise Linux)6.5`です。

1. 「現用系」と呼んでいる本番サーバ群。WWWサーバとDBサーバがあります。
* 「待機系」と呼んでいる冗長構成の控えサーバ群。現用系と同様にWWWサーバとDBサーバがあります。
* それ以外に、バックアップサーバ(ただのファイルサーバ)。

この構成がそもそも一般的なものなのかも分からないのですが、もし現用系に問題が発生したら、待機系のIPアドレスを現用系のIPアドレスに書き換え、その時点で最新のDBバックアップを待機系に復元して復旧する、というもの。
ちなみにこのDBバックアップ、最新のものは当日早朝にコールドで取得したものになります。(汗)

で、この「当日早朝にコールドで取得」した現用系のDBバックアップは、早朝cronで実行されるバックアップバッチにより、冗長化の名の元に以下に`SSH`で転送されます。

- バックアップサーバの特定ディレクトリ
- 待機系DBサーバのバックアップファイル格納用ディレクトリ　←
- 現用系DBサーバのバックアップファイル格納用ディレクトリ　←

自分がこのシステムに関わり始めた時からこういう仕様なので、もうこの仕様にどうこう言えませんし、現実問題こうなっているので仕方がありません。

### 検証環境の構築、とちょっと本題に入っていく
今までは、待機系≒動作確認用のような位置付けになっていたのですが(汗)、とある別のシステムから古い2Uサーバを移管することができたので、そこに検証環境を構築することになりました。

ライセンスや今後の見通しを考えて、OSは`RHEL6.5`⇒`CentOS6.5`に変更です。
`Sendmail`もやめて`Postfix`です。ｗｗｗ

各サーバの構築手順書があるので、適宜検証環境の内容に読み替えて作業を開始しました。
実環境との一番の大きな差異は、**【3台あるサーバの全ての役割を一台に集約する】**ということです。

前述のとおり、バックアップを各サーバの特定ディレクトリに転送しているので、ここだけちょっと面倒でした。
バッチの内容は変更しないまま、接続先サーバや保存先ディレクトリをパラメータ類の変更で対応しなければなりません。

### 問題発生
WebサーバやDBサーバは特に問題ありませんでした。
Webアプリケーションもすんなり動作し始めました。

しかし、バックアップバッチだけがどうしても上手く行きませんでした。

公開鍵認証方式にして、`SSH`接続にパスワードが不要となるようにしているのに、`SSH`実行の都度パスワードが求められてしまうのです。

実環境の方では、前述のとおり「現用系DBサーバのバックアップファイル格納用ディレクトリ」つまり自分自身のディレクトリに対して`SSH`接続でファイル転送しているので、問題はないはずです。
不要な個所の設定まで環境に合わせて変更してしまったか…そもそも`RHEL`と`CentOS`とでconfigファイルとかに差異があるのか…調べても調べても分かりませんでした。

### 鍵の生成と転送の手順(コマンド)

```sh
su - hoge #鍵生成ユーザに切り替え
cd ~/.ssh

#鍵生成
#本来 -t は要らないと思いますが、手順書がそうなっているので忠実に。
#パスフレーズは全て空。
ssh-keygen -t rsa

#鍵転送
#念のため、4パターン全て実施しました。
ssh-copy-id -i id_rsa.pub hoge@127.0.0.1
ssh-copy-id -i id_rsa.pub hoge@localhost
ssh-copy-id -i id_rsa.pub hoge@hostsに書いたホスト名
ssh-copy-id -i id_rsa.pub hoge@イントラの固定IPアドレス

#動作確認…パスワードが要求される。汗
ssh hoge@127.0.0.1 touch /tmp/ssh_test
ssh hoge@localhost touch /tmp/ssh_test
ssh hoge@hostsに書いたホスト名 touch /tmp/ssh_test
ssh hoge@固定IPアドレス touch /tmp/ssh_test
```

### 調査
* 鍵生成ユーザがrootだったりしない？？　⇒　問題なし
* `sshd_config`とか`ssh_config`に実環境と差異はない？　⇒　軽微な差異はあったが合わせても解消せず

* `OpenSSH`のバージョン違いとか？　⇒　両方とも`OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013`で同一
* `/var/hoge/.ssh/`配下の`authorized_keys`と`known_hosts`の各ファイルの内容に問題は？　⇒　登録した`127.0.0.1`、`localhost`、`hosts`に書いたホスト名、イントラの固定IPアドレス、全てちゃんと登録されている
* `ssh-keygen`コマンドを`dsa`で実施　⇒　変わりなし…
* ホームディレクトリおよび配下のディレクトリ・ファイル(特に`.ssh`)のアクセス権設定が不適切だと同様の現象が起きる、という情報　⇒　問題なし…

```
-rw------- 1 hoge hoge 3906 11月  9 10:32 2018 authorized_keys
-rw------- 1 hoge hoge 1675 11月  9 10:16 2018 id_rsa
-rw-r--r-- 1 hoge hoge  393 11月  9 10:16 2018 id_rsa.pub
-rw-r--r-- 1 hoge hoge 3537 11月  9 10:36 2017 known_hosts
```

* `/var/log/secure`の出力内容を確認…鍵見に行ってない…

```
Nov  9 16:01:42 backup-t su: pam_unix(su-l:session): session opened for user hoge by root(uid=0)
Nov  9 16:01:54 backup-t sshd[3512]: Accepted password for hoge from ::1 port 40532 ssh2
Nov  9 16:01:54 backup-t sshd[3512]: pam_unix(sshd:session): session opened for user hoge by (uid=0)
Nov  9 16:01:57 backup-t sshd[3516]: Received disconnect from ::1: 11: disconnected by user
Nov  9 16:01:57 backup-t sshd[3512]: pam_unix(sshd:session): session closed for user hoge
Nov  9 16:01:59 backup-t su: pam_unix(su-l:session): session closed for user hoge
```

* `ssh`コマンドを`-v`スイッチ付けてデバッグモードで実行…何で鍵認証にならないのか分からん…

```
[hoge@backup-t ~]$ ssh -v localhost
OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to localhost [::1] port 22.
debug1: Connection established.
debug1: identity file /var/hoge/.ssh/identity type -1
debug1: identity file /var/hoge/.ssh/identity-cert type -1
debug1: identity file /var/hoge/.ssh/id_rsa type 1
debug1: identity file /var/hoge/.ssh/id_rsa-cert type -1
debug1: identity file /var/hoge/.ssh/id_dsa type -1
debug1: identity file /var/hoge/.ssh/id_dsa-cert type -1
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3
debug1: match: OpenSSH_5.3 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_5.3
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
debug1: Host 'localhost' is known and matches the RSA host key.
debug1: Found key in /var/hoge/.ssh/known_hosts:2
debug1: ssh_rsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_500' not found

debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_500' not found

debug1: Unspecified GSS failure.  Minor code may provide more information


debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_500' not found

debug1: Next authentication method: publickey
debug1: Trying private key: /var/hoge/.ssh/identity
debug1: Offering public key: /var/hoge/.ssh/id_rsa
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Trying private key: /var/hoge/.ssh/id_dsa
debug1: Next authentication method: password
```

もうあんまりにも分からな過ぎてお手上げ状態だったため、[teratail](https://teratail.com/questions/157155)で質問しました。

### 結論
「これ！」というハッキリした理由は分からなかったのですが、原因はまさかの。
**【ユーザアカウントのホームディレクトリが`/var`配下だから！】**(汗)

新規ユーザを作成して試してみました。

```sh
#/home配下に明示的にホームディレクトリを作成して実施
useradd -d /home/ssh_test_home ssh_test_home
passwd ssh_test_home
su - ssh_test_home
cd ~/.ssh
ssh-keygen
ssh-copy-id -i id_rsa.pub ssh_test_home@localhost

#さて結果は！！！
ssh ssh_test_home@localhost touch /tmp/ssh_test

#パスワード聞かれないで成功っ！！！！！！！！！
```

```sh
#/var配下にホームディレクトリを作成して実施
useradd -d /var/ssh_test_var ssh_test_var
passwd ssh_test_var
su - ssh_test_var
cd ~/.ssh
ssh-keygen
ssh-copy-id -i id_rsa.pub ssh_test_var@localhost

#さて結果は！！！
ssh ssh_test_var@localhost touch /tmp/ssh_test

#パスワード聞かれる…
```

`RHEL`はこんなことなかったのに、`CentOS`だとこういう現象が起きる。
OSに当てたパッチとかまで同一かどうかは確認しなかったけど(後でやろう…)、同じ`6.5`なのにこんな違いが出ることがあるんですね…

ユーザのホームディレクトリを何かしらの理由で`/home`以外を指定したら、こんな現象が起こるというお話しでした。

### 追記・完全に解決(2018/11/13)
さすが初心者ですね…完全に存在に気づいていませんでした。`SELinux`。
CentOS6以降はSELinuxがデフォルトで有効なんですね…

@error_401 さんにコメントでご指摘いただいたので確認しました。
`getenforce`コマンドを叩いたところ`enforcing`が返ってきたので、`/etc/selinux/config`を開いて`disabled`に変更して再起動…無事パスワードなしで接続できるようになりました。

RHELはデフォルトだと`SELinux`が有効なのか無効なのかは分かりませんが、とりあえずこれは手順書に書かないとダメな設定でした。

@error_401 さんありがとうございました。

### 更に追記・備忘録
[teratail](https://teratail.com/questions/157155)でいただいたコメントをメモしておきます。

`audit`ログに、`authorized_keys`のread拒否のログが出るんですね。
しかし…auditログ読めん…どっからどこまでが一塊なんだ…orz

```
type=AVC msg=audit(1541964001.483:4117): avc:  denied  { read } for  pid=23900 comm="sshd" name="authorized_keys" dev=dm-0 ino=1967655 scontext=unconfined_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:var_t:s0 tclass=file
```

以下のコマンドでコンテキスト変更すると`SELinux`有効のままでもパスワード聞かれることなく認証できるようになる、ということでしたが、今回は`SELinux`を無効にするのみの対応としました。

```sh
chcon -R unconfined_u:object_r:ssh_home_t:s0 .ssh/
```