Windows Server 2019 EC2インスタンスでSSHサーバーを有効にする

しばたです。
「ドキュメントがあるから余裕でしょ。」と高を括っていたら予想以上にハマったので本記事で共有します。

前提

WindowsではWindows 10 Fall Creators Update(1709)からOSに標準でOpenSSHのポートであるWin32-OpenSSHが組み込まれており、サーバーOSもその流れを受けて半期チャネルではWindows Server version 1803から、長期サービスチャネルではWindows Server 2019からOSにOpenSSHのサーバーおよびクライアント機能が組み込まれています。

SSHサーバー(sshd)の機能はデフォルトではオフにされており、SSHサーバーを利用するには機能を有効にして所定の初期設定を行う必要があります。

作業手順

作業手順は公式にはMicrosoft Docsに記載されています。

基本的にはこちらの手順に従えば良いのですが、Windows独自の仕様やOpenSSHのバージョンによる変更点がそこそこあり、知ってしまえばどうということはないのですが、初見ではハマってしまうポイントが結構ありました。
また、本記事ではEC2インスタンス上にSSHサーバーを立てるので鍵設定の部分に関しては独自の手順を取り入れています。

やってみた

それでは本題に入ります。
本記事ではRDPを使いAdministratorでOSにログインした状態をスタート地点とし、Windows PowerShellのコンソール上で各種作業を進めていきます。

1. 機能の有効化

はじめにAdd-WindowsCapabilityコマンドレットを使いSSHサーバーの機能を有効にし、sshdサービスの初期設定を行います。

# Install the OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# Configure sshd service setting
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

2. sshd_configの設定変更

Windows Server 2019のsshdではsshd_config%programdata%\ssh\sshd_configにあります。
(sshd.exeのあるディレクトリでは無いので注意。Ver.1.0.0.0-betaからの変更点になります。)

デフォルトでは公開鍵認証とパスワード認証が有効になっています。
本記事では公開鍵認証のみを明示して許可する設定に変更します。

# 残念ながらWindowsにはsedが標準搭載されていないので気合で sshd_config を修正
$sshdConfigPath = Join-Path $env:ProgramData 'ssh\sshd_config'
Get-Content $sshdConfigPath -Encoding Ascii -Raw | 
    ForEach-Object {
        $c = $_ -replace '#PubkeyAuthentication', 'PubkeyAuthentication'
        $c = $c -replace '#PasswordAuthentication yes', 'PasswordAuthentication no'
        $c | Out-File -FilePath $sshdConfigPath -Encoding ascii
    }

# サービス再起動
Restart-Service sshd

3. 公開鍵設定

次に公開鍵の設定を行います。
通常のSSHサーバーであればssh-keygenなどを使い鍵を生成しますが、今回はEC2インスタンスなのでキーペアが既に存在しています。
EC2キーペアの公開鍵はインスタンスメタデータから取得できますのでこれをauthorized_keysに設定してやります。

ここでWindowsの独自仕様としてsshd_configに以下の記述がされており、Administratorsグループの公開鍵は%programdata%\ssh\administrators_authorized_keysに設定する必要があります。
(本件に該当するGitHubのIssueはこちら)

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

administrators_authorized_keysの設定は以下のコマンドで行います。

# インスタンスメタデータから公開鍵を取得し administrators_authorized_keys に設定
$administratorsKeyPath =  Join-Path $env:ProgramData 'ssh\administrators_authorized_keys'
Invoke-RestMethod -Uri http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key/ |
    Out-File -FilePath $administratorsKeyPath -Encoding ascii

そして作成したばかりのadministrators_authorized_keysには不要なアクセス権(Authenticated Usersのアクセス権)が付与されているのでこれを除外します。

# フォルダのアクセス権を取得
$acl = Get-Acl $administratorsKeyPath
# アクセス権の継承を解除
$acl.SetAccessRuleProtection($true,$true)
# アクセスルールを除去
$removeRule = $acl.Access | Where-Object { $_.IdentityReference -eq 'NT AUTHORITY\Authenticated Users' }
$acl.RemoveAccessRule($removeRule)

# アクセス権を更新
$acl | Set-Acl -Path $administratorsKeyPath

4. (Optional) デフォルトシェルの変更

Windows版OpenSSHのデフォルトシェルはコマンドプロンプトです。
シェルの指定はレジストリにあり、以下の様にするとデフォルトシェルをPowerShellに変更可能です。

# change default shell
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

以上で設定は完了です。

接続確認

最後にSSHクライアントからこのサーバーに接続して動作確認をしてみます。

無事接続され、シェルもWindows PowerShellになっています。

補足

こうやって記事にするとあっさりした手順で済んでいますが、記事を書くに至るまでには結構調査の時間がかかりました。
補足として調査の役に立ったTipsを紹介します。

デバッグログ

SSHサーバー側のログ設定はsshd_configに記載されており、SyslogFacilityでログの出力先を、LogLevelでログの詳細度を設定できます。
サーバー側のログ設定を以下の様にすると詳細な情報を直ちに取得できます。

SyslogFacility LOCAL0
LogLevel DEBUG3
  • SyslogFacility LOCAL0
    • ログの出力先をローカルファイルに変更 (ログは%programdata%\ssh\log\に吐かれる)
  • LogLevel DEBUG3
    • 詳細なログ出力に変更。DEBUG3未満のレベルだと欲しい情報が取れないことが多かった

OpenSSHUtils モジュール

各種ファイルのアクセス権をよしなに設定してくれるOpenSSHUtilsがPowerShell Galleryで公開されています。

# OpenSSHUtils モジュールのインストール
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name OpenSSHUtils -Scope CurrentUser -Force -SkipPublisherCheck

以前は同等のモジュールファイルがsshdと同じディレクトリにあった記憶があるのですが、いつの間にか独立したモジュールになっていました。

このモジュールにあるRepair-AuthorizedKeyPermissionコマンドレットを使うとauthorized_keysファイルのアクセス権を設定できるのですが、残念ながらauthorized_keysの置き場所が~\.ssh\authorized_keys決め打ちとなっており、今回のadministrators_authorized_keysでは使用できませんでした。

本記事では使用しませんでしたが環境によってはこのモジュールを使うとより楽にSSHの設定が可能になるはずです。