WindowsにSSH公開鍵認証でログインしようとしてハマった
WindowsにOpenSSHをインストールしてパスワードなしのSSH公開鍵認証を設定しようとしたところ、Linuxとは異なるいくつかの罠にはまったのでその記録。
環境
- サーバー:Windows 11 Pro(OpenSSH for Windows 9.5)
- クライアント:Debian Linux(OpenSSH 10.0)
- ログインユーザー:
ansible
基本的な設定手順
この手順で実行すれば成功する。
1. Windows側でユーザーを作成し、ログオン(重要)
ユーザー作成はコントロールパネルでもコンピューターの管理でもいいが、そのあと mkdir とかでユーザーディレクトリを作ってはいけない。 必ず一度対話型ログオンをしておくこと。
2. クライアント側で鍵ペアを生成
3. SSHサーバーをインストール
名前を確認してから Add-WindowsCapability でインストール
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Add-WindowsCapability -online -name OpenSSH.Server~~~~0.0.1.0
サービスの状態を確認しつつ起動し、自動開始に設定する。
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
書き換えた後はサービスを再起動
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」と表示されるため成功したように見えてしまう。実際にはファイルは作成されていない。
対策: PowerShellのコマンドを直接実行して公開鍵をコピーする。
③ .ssh ディレクトリ自体の権限も厳格に管理される
authorized_keys の権限だけ絞っても、親の .ssh ディレクトリに Users や Everyone が残っていると認証が拒否される。ディレクトリと authorized_keys の両方の権限を設定する必要がある。
トラブルシュートのコツ
認証が通らないときはクライアント側で -v オプションをつけて接続する。
Offering public key の直後に Authentications that can continue が出て鍵が拒否されている場合は、サーバー側のイベントログを確認する。