コンテンツにスキップ

WindowsにSSH公開鍵認証でログインしようとしてハマった

WindowsにOpenSSHをインストールしてパスワードなしのSSH公開鍵認証を設定しようとしたところ、Linuxとは異なるいくつかの罠にはまったのでその記録。

環境

  • サーバー:Windows 11 Pro(OpenSSH for Windows 9.5)
  • クライアント:Debian Linux(OpenSSH 10.0)
  • ログインユーザー:ansible

基本的な設定手順

この手順で実行すれば成功する。

1. Windows側でユーザーを作成し、ログオン(重要)

ユーザー作成はコントロールパネルでもコンピューターの管理でもいいが、そのあと mkdir とかでユーザーディレクトリを作ってはいけない。 必ず一度対話型ログオンをしておくこと。

2. クライアント側で鍵ペアを生成

ssh-keygen -t ed25519

3. SSHサーバーをインストール

名前を確認してから Add-WindowsCapability でインストール

Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Add-WindowsCapability -online -name OpenSSH.Server~~~~0.0.1.0

サービスの状態を確認しつつ起動し、自動開始に設定する。

Get-Service -Name sshd
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

4. sshd_configの確認

C:\ProgramData\ssh\sshd_config で以下を確認する。

PermitRootLogin no # お好みで
PubkeyAuthentication yes
PasswordAuthentication no # お好みで
AuthorizedKeysFile .ssh/authorized_keys

また、管理者ユーザーの場合は末尾の以下のブロックをコメントアウトしておく。
コメントアウトしないと authorized_keys の参照先が別のパスになってしまう。

# Match Group administrators
#     AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

書き換えた後はサービスを再起動

Start-Service sshd

5. 公開鍵の登録

ssh-copy-id はWindows Serverに対して使えないので(後述)、以下のコマンドで直接コピーする。

cat ~/.ssh/id_ed25519.pub | ssh user@server "powershell -Command \"\$input | Out-File -Encoding utf8 -FilePath 'C:\\Users\\ansible\\.ssh\\authorized_keys' -Append\""

6. 権限の設定

.ssh ディレクトリと authorized_keys の両方から余計な権限を取り除く。

icacls "C:\Users\ansible\.ssh" /inheritance:r `
    /grant "NT AUTHORITY\SYSTEM:(OI)(CI)(F)" `
    /grant "BUILTIN\Administrators:(OI)(CI)(F)"

icacls "C:\Users\ansible\.ssh\authorized_keys" /inheritance:r `
    /grant "NT AUTHORITY\SYSTEM:(F)" `
    /grant "BUILTIN\Administrators:(F)"

ハマりポイント

① 手動でプロファイルディレクトリを作ってはいけない

ansibleユーザーを作成する前に(あるいは作成直後に)C:\Users\ansible を手動で作成しておくと、ユーザーの初回ログオン時にWindowsがそのディレクトリが既に存在することを検知し、C:\Users\ansible.hostname(ホスト名サフィックス付き)という別のディレクトリをプロファイルとして作成してしまう。

SSHデーモンは実際のプロファイルディレクトリを参照するため、C:\Users\ansible\.ssh\authorized_keys に鍵を置いても読まれない。

対策: ユーザー作成後はWindowsの初回ログオン時にプロファイルディレクトリを自動生成させる。手動では作らない。

ssh-copy-id はWindows Serverに対して使えない

ssh-copy-id は内部で exec sh を実行しようとするが、Windows側にshellがないためコマンドが失敗する。厄介なことに、エラーメッセージが出ていても最終的に「Number of key(s) added: 1」と表示されるため成功したように見えてしまう。実際にはファイルは作成されていない。

'exec' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
Number of key(s) added: 1   ← 嘘

対策: PowerShellのコマンドを直接実行して公開鍵をコピーする。

.ssh ディレクトリ自体の権限も厳格に管理される

authorized_keys の権限だけ絞っても、親の .ssh ディレクトリに UsersEveryone が残っていると認証が拒否される。ディレクトリと authorized_keys の両方の権限を設定する必要がある。


トラブルシュートのコツ

認証が通らないときはクライアント側で -v オプションをつけて接続する。

ssh -v ansible@server

Offering public key の直後に Authentications that can continue が出て鍵が拒否されている場合は、サーバー側のイベントログを確認する。

Get-WinEvent -LogName "OpenSSH/Operational" -MaxEvents 30 | Select-Object TimeCreated, Message | Format-List