🚀

Linux(Ubuntu)へ公開鍵認証でSSH接続する手順と仕組み

に公開

概要

今回のシナリオでは、同じLANに接続された MacOSをクライアント側、Linux(Ubuntu)をサーバ側 として設定し、公開鍵認証を用いてSSH接続を行う方法を整理します。

サーバ(Ubuntu)側の準備

OpenSSHサーバをインストール

Ubuntu側にSSHサーバをインストールし、接続を受け付けられるようにします。

# パッケージリスト更新
$ sudo apt update

# OpenSSHサーバをインストール
$ sudo apt install -y openssh-server

# インストールされたことを確認
$ dpkg -l | grep openssh
ii openssh-server  secure shell (SSH) server, for secure access from remote machines
ii openssh-sftp-server  secure shell (SSH) sftp server module, for SFTP access from remote machines

active (running)になっていればOKです。これでUbuntu側でSSH接続を待ち受けてくれます。

systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)
     Active: active (running) since Thu 2025-08-28 06:57:56 JST; 1min 49s ago
TriggeredBy: ● ssh.socket
       Docs: man:sshd(8)
             man:sshd_config(5)
    Process: 60490 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
   Main PID: 60492 (sshd)
      Tasks: 1 (limit: 4319)
     Memory: 3.3M (peak: 19.8M)
        CPU: 179ms

パスワード認証での接続確認

まずはシンプルにパスワード認証で接続します。

ssh [user名]@[IPアドレス]
  • ユーザー名 は Ubuntu 側のシェルプロンプトに表示されている ***@hostname:~$ の *** 部分です。
  • IPアドレス はサーバで ip addr show を実行して確認します。
ip addr show
#略
    wlan0:
      inet 192.168.10.7/24

接続すると、以下のようにパスワードを求められます。入力するとログイン完了です。

ssh [user名]@192.168.10.7
# 略
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
[user名]@192.168.10.7's password: 
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-1020-raspi aarch64)
[user名]@xxxxxx:~$

公開鍵認証での接続

公開鍵・秘密鍵を作成する

接続したい側(クライアント)で、ssh-keygenを使って公開鍵と秘密鍵を作成します。

$ ubuntu-test % ssh-keygen -t rsa -f ~/.ssh/ubuntu-test/id_rsa
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /Users/*****/.ssh/ubuntu-test/id_rsa
Your public key has been saved in /Users/*****/.ssh/ubuntu-test/id_rsa.pub
The key fingerprint is:
# 以下略

$ ubuntu-test % ls
id_rsa		id_rsa.pub

ディレクトリやファイル名を何も指定しない場合、~/.ssh/id_rsa(秘密鍵)、~/.ssh/id_rsa.pub(公開鍵)として作成されます。ファイル名やディレクトリを変更したい場合は、-fで指定可能です。

公開鍵をサーバにコピーする

認証の際サーバ側で公開鍵を利用するため、生成した公開鍵をサーバにコピーします。

scp ~/.ssh/ubuntu-test/id_rsa.pub [user名]@192.168.10.7:.ssh
[user名]@192.168.10.7's password: 
id_rsa.pub                   100%  583    54.8KB/s   00:00 

その後、サーバにログインして、公開鍵を~/.ssh/authorized_keysに登録します。

ssh [user名]@192.168.10.7
リモートサーバ:~/.ssh$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
# コピーしてきた公開鍵は不要なので削除
リモートサーバ:~/.ssh$ rm id_rsa.pub

authorized_keysのパーミッションを変更します。

# 変更前は、グループとその他ユーザーも閲覧や書き込みができる状態
リモートサーバ:~/.ssh$ ls -la
total 16
-rw-rw-r--  1 583 Aug 28 07:14 authorized_keys

# 所有者の閲覧・書き込みのみに制限する
リモートサーバ:~/.ssh$ chmod 600 authorized_keys 

# 変更後のパーミッション確認
リモートサーバ:~/.ssh$ ls -la
total 16
-rw-------  1 583 Aug 28 07:14 authorized_keys

なお、同様のことはssh-copy-idコマンドで1発でできます。本記事ではやっていることの内容をしっかり理解するため、手動で実施しました。

ssh-copy-id -i ~/.ssh/id_rsa.pub [user名]@192.168.10.7

接続テストをする

公開鍵認証の準備が整ったので、接続を試してみます。-iを指定し、秘密鍵のパスを指定します。

$ ssh -i ~/.ssh/ubuntu-test/id_rsa [user名]@192.168.10.7
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-1020-raspi aarch64)
# 略
[user名]@xxxxxx:~$

今度はパスワードを求められることなく接続成功します。

パスワード認証を無効化する

公開鍵認証が使えるようになったら、パスワード認証は無効化しておくとより安全です。linuxサーバ側の設定ファイル/etc/ssh/sshd_configを編集します。

具体的には、PasswordAuthenticationnoに変更します。

$ ssh -i ~/.ssh/ubuntu-test/id_rsa [user名]@192.168.10.7
リモートサーバ:~$ sudo vi /etc/ssh_sshd_config
# 略
- #PasswordAuthentication yes
+ PasswordAuthentication no
# 略

変更を反映するために、SSHサーバを再起動します。

リモートサーバ:~$ sudo systemctl restart ssh

再度パスワード認証でログインを試すと拒否され、公開鍵認証でのみ接続できるようになります。

$ ssh [user名]@192.168.10.7
[user名]@192.168.10.7: Permission denied (publickey).

当然、公開鍵認証であれば、接続可能です。

$ ssh -i ~/.ssh/ubuntu-test/id_rsa [user名]@192.168.10.7
リモートサーバ:~$

SSH公開鍵認証の仕組み

以下は、SSH公開鍵認証の流れを示した図です。

公開鍵認証の流れをログと対応づけて見てみましょう。sshコマンドに-vvvを付けると、クライアントとサーバのやり取りを詳細に表示され、公開鍵提示や署名送信の流れも確認できます。

①ユーザー名&公開鍵を提示

debug1: Offering public key: /Users/*****/.ssh/ubuntu-test/id_rsa RSA SHA256:...
debug3: send packet: type 50       ← SSH_MSG_USERAUTH_REQUEST

クライアントが「この公開鍵を使って接続したいので、認証お願いします!」といった内容の認証リクエストを送ります。具体的にはリクエストフォーマットはRFC 4252 - The Secure Shell (SSH) Authentication Protocolに記載があります。

ここに出ているtype 50SSH_MSG_USERAUTH_REQUESTを表す値であり、SSHのユーザー認証リクエストを示しています。

②署名を要求

SSHサーバ側は、①で送付された公開鍵を確認します。具体的には、その公開鍵がサーバ側に登録されているか(=~/.ssh/authorized_keysに記載されているか)を確認します。

登録済みであることが確認できた場合、サーバはSSH_MSG_USERAUTH_PK_OK(この公開鍵で認証を進めて良い)という返答を返します。

debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 60    ← SSH_MSG_USERAUTH_PK_OK
debug1: Server accepts key: /Users/*****/.ssh/ubuntu-test/id_rsa RSA SHA256:...

このやり取りが、サーバからクライアントに対して「秘密鍵を使って署名を行い、もう一度リクエストを送ってください」という署名要求の役割を果たしています。

③署名を送信

①で提示した公開鍵がサーバに受け入れられたため、クライアントはペアである秘密鍵を使って署名を作成し、その署名をサーバに送信します。

debug3: sign_and_send_pubkey: signing using rsa-sha2-512 ...
debug3: send packet: type 50

このとき送信されるのもSSH_MSG_USERAUTH_REQUESTですが、今度は署名付きのリクエストになっています。

④(検証成功したら)Authenticated

③で送信した署名をサーバ側が検証します。署名の検証が成功すると、サーバから認証成功を示すSSH_MSG_USERAUTH_SUCCESSが返却されます。

debug3: receive packet: type 52  ← SSH_MSG_USERAUTH_SUCCESS
Authenticated to 192.168.10.7 ([192.168.10.7]:22) using "publickey".

ログ抜粋まとめ

最後に大事なログだけ抜き出してまとめると、次のようになります。

$ ssh -i ~/.ssh/ubuntu-test/id_rsa [user名]@192.168.10.7 -vvv
# 略
# ①ユーザー名&公開鍵を提示
debug1: Offering public key: /Users/*****/.ssh/ubuntu-test/id_rsa RSA SHA256:...
debug3: send packet: type 50
# 略
# ②署名を要求
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 60    ← SSH_MSG_USERAUTH_PK_OK
debug1: Server accepts key: /Users/*****/.ssh/ubuntu-test/id_rsa RSA SHA256:...
# 略
# ③署名を送信
debug3: sign_and_send_pubkey: signing using rsa-sha2-512 ...
debug3: send packet: type 50
# 略
# ④(検証成功したら)Authenticated
debug3: receive packet: type 52  ← SSH_MSG_USERAUTH_SUCCESS
Authenticated to 192.168.10.7 ([192.168.10.7]:22) using "publickey".

サーバ側は何を検証しているか

公開鍵認証では、サーバ側は単に「公開鍵が登録されているか」を確認するだけではなく、クライアントが秘密鍵を本当に持っているか、そして認証に必要なデータが改ざんされていないかを検証しています。

サーバ側でハッシュを計算

セッションID、ユーザー名、公開鍵などの認証データをもとに、サーバ自身でもハッシュ値を作成します。

署名を公開鍵で復号

クライアントが送ってきた署名を公開鍵で復号します。復号できるということは、その署名が対応する秘密鍵で作られたものであることを意味します。つまり、クライアントが秘密鍵を保持している=正しいユーザーであることの証明となります。

ハッシュ値の一致を確認

復号して得られたハッシュ値と、サーバ自身が計算したハッシュ値を比較します。一致すれば、認証に関わるデータが途中で改ざんされていないことが確認できます。

このようにサーバは、

  • 秘密鍵を保持しているユーザー本人であること
  • やり取りされる認証データが改ざんされていないこと

の2点を検証することで、公開鍵方式によるユーザー認証を成立させています。

参考

https://tex2e.github.io/rfc-translater/html/rfc4252.html

Discussion