OpenSSHの証明書認証を試す
OpenSSHの証明書認証について
ユーザ認証
- CA秘密鍵で署名されたユーザ証明書(公開鍵)の署名情報を利用して認証する。
- SSHサーバにはCA公開鍵を登録し、ユーザから送られてきユーザ証明書を検証する。
公開鍵をユーザホームディレクトリ配下の ~/.ssh/authorized_keys に記載しなくてよい。(むしろ置いてはいけない?)
ホスト認証
- 接続先のSSHサーバが目的のホストであることを認証して詐称を防ぐ技術。
- SSHサーバにはCA秘密鍵で署名したホストキーをインストール、SSHクライアントのユーザ領域にはCA公開鍵の情報を保管する。
- SSHサーバから送られてきたホストキーが、信頼しているCA証明書で署名されたものを確認する。
~/.ssh/known_hosts にはSSHサーバのホストキーではなてく、CA公開鍵の情報を記載してやる。
→ 初回SSH接続時に通常だとホストキーのフィンガープリントが表示され「信頼しますか?」と表示されるところの処理が無くなる
テスト環境
サーバ側
Raspberry Pi OS > KVM > Debian12
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
$ cat /etc/debian_version
12.0
$ uname -a
Linux debian12 6.1.0-9-arm64 #1 SMP Debian 6.1.27-1 (2023-05-08) aarch64 GNU/Linux
クライアント側
Raspberry Pi OS > Docker > AmazonLinux2023
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2023"
ID="amzn"
ID_LIKE="fedora"
VERSION_ID="2023"
PLATFORM_ID="platform:al2023"
PRETTY_NAME="Amazon Linux 2023.5.20240708"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023"
HOME_URL="https://aws.amazon.com/linux/amazon-linux-2023/"
DOCUMENTATION_URL="https://docs.aws.amazon.com/linux/"
SUPPORT_URL="https://aws.amazon.com/premiumsupport/"
BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023"
VENDOR_NAME="AWS"
VENDOR_URL="https://aws.amazon.com/"
SUPPORT_END="2028-03-15"
$ cat /etc/amazon-linux-release
Amazon Linux release 2023.5.20240708 (Amazon Linux)
$ uname -a
Linux e1c64185cb26 6.6.31+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.6.31-1+rpt1 (2024-05-29) aarch64 aarch64 aarch64 GNU/Linux
普通の公開鍵認証
クライアントの鍵ペアを作成
$ ssh-keygen -q -t ed25519
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
$ ls -l ~/.ssh/id_ed25519*
-rw------- 1 user user 399 Nov 2 06:13 /home/user/.ssh/id_ed25519
-rw-r--r-- 1 user user 95 Nov 2 06:13 /home/user/.ssh/id_ed25519.pub
公開鍵を ~/.ssh/authorized_keys に追記
$ cat ~/.ssh/id_ed25519.pub | tee -a ~/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHylCHNgAqZNJrunlbek2+PiNNU/9jo/XjiJToRquOOq user@debian12
接続テスト
ssh -i ./id_ed25519 user@192.168.11.120
このときサーバ側では以下のようなログが出る。
# journalctl -u ssh
Nov 02 15:10:41 debian12 sshd[2953]: Accepted publickey for user from 192.168.11.250 port 55696 ssh2: ED25519 SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os
パスワード認証を禁止したい場合(証明書認証に失敗したあとパスワード認証にフォールバックしたくない場合)は設定を変更する
# sed -i -e '/#PasswordAuthentication/ s/.*/PasswordAuthentication no/' /etc/ssh/sshd_config
# systemctl restart ssh
証明書認証の準備
CA証明書作成
CA証明書(署名するための鍵ペア)を作成する
$ ssh-keygen -q -t ed25519 -f ca.key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
$ ls -l ca.key*
-rw------- 1 root root 399 Nov 2 06:06 ca.key
-rw-r--r-- 1 root root 95 Nov 2 06:06 ca.key.pub
CA証明書と言われるが、ただのSSH鍵ペアである。
ユーザ証明書作成
クライアントの公開鍵に署名してユーザ証明書を作成する。
シリアルと有効期限を指定する例
$ ssh-keygen -s ca.key -I certificate-test -n user -z $(date +%Y%m%d%H%M) -V +365d id_ed25519
Signed user key id_ed25519-cert.pub: id "certificate-test" serial 202411020544 for user valid from 2024-11-02T05:43:00 to 2025-11-02T05:44:56
$ ssh-keygen -L -f id_ed25519-cert.pub
id_ed25519-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Public key: ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os
Signing CA: ED25519 SHA256:p12hRLK8xDAv+ArfcrZS1loLBUXkTC3JRtlRyYZvpwQ (using ssh-ed25519)
Key ID: "certificate-test"
Serial: 202411020544
Valid: from 2024-11-02T05:43:00 to 2025-11-02T05:44:56
Principals:
user
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc
- 証明書なので有効期限は設定したい。
- 明示的に無効化するにはシリアルの登録が必要
- ここでは指定していないが、接続元ホストを限定するオプションもあるようだ。
作成した証明書をユーザに配布する。
CA公開鍵の配置
SSHサーバにCA公開鍵を配置する。
# cp ~user/work/ca.key.pub /etc/ssh/ca.key.pub
# chown root: /etc/ssh/ca.key.pub
# echo "TrustedUserCAKeys /etc/ssh/ca.key.pub" | tee -a /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca.key.pub
ホスト証明書の作成
SSHホスト公開鍵をCA秘密鍵で署名して、ホスト証明書を作成する。
# ssh-keygen -s ~user/work/ca.key -h -I certificate-test /etc/ssh/ssh_host_ed25519_key.pub
Signed host key /etc/ssh/ssh_host_ed25519_key-cert.pub: id "certificate-test" serial 0 valid forever
# ssh-keygen -L -f /etc/ssh/ssh_host_ed25519_key-cert.pub
/etc/ssh/ssh_host_ed25519_key-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com host certificate
Public key: ED25519-CERT SHA256:RspUz/oxoReoB+85SbuIWjzAl9bfg8cNRzLjxtwEPfQ
Signing CA: ED25519 SHA256:p12hRLK8xDAv+ArfcrZS1loLBUXkTC3JRtlRyYZvpwQ (using ssh-ed25519)
Key ID: "certificate-test"
Serial: 0
Valid: forever
Principals: (none)
Critical Options: (none)
Extensions: (none)
# echo "HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub" | tee -a /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
sshd 再起動
# systemctl restart ssh
接続テスト
ユーザ側で信頼するCA公開鍵を設定
cat << EOF >> known_hosts
@cert-authority 192.168.11.120 $(cat ca.key.pub)
EOF
~/.ssh/authorized_keys の退避
~/.ssh/authorized_keys があると、強制的に通常の公開鍵認証になるようだ。
後述のKRLの仕組みも効かなくなるので、もしあれば予め削除する。
接続テスト
接続してみる
$ ssh -v -o UserKnownHostsFile=./known_hosts -i ./id_ed25519 -F /dev/null user@192.168.11.120
ホスト証明書を利用していることを示すデバッグ情報
debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:RspUz/oxoReoB+85SbuIWjzAl9bfg8cNRzLjxtwEPfQ, serial 0 ID "certificate-test" CA ssh-ed25519 SHA256:p12hRLK8xDAv+ArfcrZS1loLBUXkTC3JRtlRyYZvpwQ valid forever
debug1: Host '192.168.11.120' is known and matches the ED25519-CERT host certificate.
ユーザ証明書を利用していることを示すデバッグ情報
debug1: Will attempt key: ./id_ed25519 ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os explicit
debug1: Offering public key: ./id_ed25519 ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os explicit
debug1: Server accepts key: ./id_ed25519 ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os explicit
サーバ側でもユーザ情報で認証されたことを示すログが出力される
# journalctl -u ssh
Nov 02 08:50:55 debian12 sshd[2734]: Accepted publickey for user from 192.168.11.250 port 57364 ssh2: ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os ID certificate-test (serial 0) CA ED25519 SHA256:p12hRLK8xDAv+ArfcrZS1>
ssh config を記載して利用すると簡単。
Host myalias
HostName 192.168.11.120
User user
IdentityFile ./id_ed25519
UserKnownHostsFile ./known_hosts
ssh config を利用した接続。
ssh -v -F ./config myalias
scp でも利用できる
$ scp -v -F config krl myalias:/tmp
証明書を無効化
無効化すべきユーザ証明書のシリアルのリストを作成する。
serial:202411020544
作成したリストに基づいて、KRL(Key Revocation List)ファイルを作成する(※ krl 更新時は -u を指定する)
$ ssh-keygen -k -f krl -s ca.key.pub krl.list
Revoking from krl.list
作成したKRLファイルを確認する
$ ssh-keygen -Q -l -f krl
# KRL version 0
# Generated at 20241102T054916
# CA key ssh-ed25519 SHA256:p12hRLK8xDAv+ArfcrZS1loLBUXkTC3JRtlRyYZvpwQ
serial: 202411020544
$ ssh-keygen -Q -f krl id_ed25519-cert.pub
id_ed25519-cert.pub ((null)): REVOKED
サーバに配置して、sshd を再起動する。
# mv krl /etc/ssh
# echo "RevokedKeys /etc/ssh/krl" | tee -a /etc/ssh/sshd_config
RevokedKeys /etc/ssh/krl
# systemctl restart ssh
無効化したユーザ証明書でアクセスすると接続失敗となる。
サーバ側では以下のログが出る。
# journalctl -u ssh
Nov 03 06:08:20 debian12 sshd[3368]: error: Authentication key ED25519-CERT SHA256:tPR4rIIfnnh7gHp9sqNnrDGv2nukqx8QwlS2SxTC1Os revoked by file /etc/ssh/krl
Nov 03 06:08:20 debian12 sshd[3368]: Connection closed by authenticating user user 192.168.11.250 port 53332 [preauth]
Discussion