「Linux踏み台を使わずにWindowsインスタンスへのリモートデスクトップ接続をSSHトンネル化する」のをUserDataを用いて設定自動化してみた

みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。

前回の記事で「Linux踏み台を使わずにWindowsインスタンスへのリモートデスクトップ接続をSSHトンネル化する」方法についてご紹介しました。

この方法は Windows インスタンスのみ利用するという点では便利なのですが、最初のサーバー側の設定がちょっと面倒かもしれません。

ということで、サーバー側の事前設定を自動化してみました。

設定自動化する範囲

前回の記事での
「1. 対象 Windows サーバーで OpenSSH Server の設定を行う」
の部分をまるっと自動化します。

設定している内容は以下の通りです。

  • OpenSSH Server 機能を有効化
  • OpenSSH Server サービスの自動起動設定
  • OpenSSH Server の config 設定
  • 公開鍵ファイルの配置
  • OpenSSH Server サービスを再起動して設定を反映

設定自動化の方法

インスタンスの作成時にスクリプトを自動実行させる仕組みである UserData を使います。

マネジメントコンソールでインスタンスを作成する場合は、「高度な詳細」を展開して「ユーザーデータ」の設定を行います。

UserData に指定するスクリプトの内容は以下の通りです。

<powershell>
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd
Move-Item "${Env:ProgramData}\ssh\sshd_config" "${Env:ProgramData}\ssh\sshd_config.original"
$data = "PubkeyAuthentication yes"
$data += "`n" + "PasswordAuthentication no"
Out-File -FilePath "${Env:ProgramData}\ssh\sshd_config" -InputObject $data -Encoding ascii
New-Item -Path "${Env:USERPROFILE}" -Name ".ssh" -ItemType Directory
Invoke-RestMethod -Uri "http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key" -OutFile "${Env:USERPROFILE}\.ssh\authorized_keys"
Restart-Service -Name sshd
</powershell>

処理内容の説明

OpenSSH Server 機能を有効化 ~ サービスの自動起動設定

マイクロソフトの Windows 関連ドキュメントページに以下の情報がありました。

Windows の OpenSSH のインストール | Microsoft Docs

PowerShell を使った設定手順も書かれていましたので、そちらに準じています。

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd

2 行目で、Windows の「機能の追加」を行います。
-Name に続く名前は正確に指定する必要があります。(「チルダ ( ~ ) 」の数やバージョン番号を含む)

3 行目は、サービスの自動起動の設定です。

最後に 4 行目で、OpenSSH Server サービス (内部名: sshd ) を開始しています。
これは、前回の記事でも書いたように、一旦サービスを開始しなければ、設定ファイルなどが格納される「ssh」フォルダが作成されないためです。

OpenSSH Server の config 設定

config ファイルの設定について、前回の記事ではデフォルトの config ファイルを修正する方法を取っていましたが、今回は「必要な設定項目のみを記述した config ファイルを新規作成する」方法にしています。
(インスタンス作成直後で、既存の設定内容を考慮する必要がないので、これで問題ないと思います)

ここでいう「必要な設定項目」とは、以下の 2 つです:

  • PubkeyAuthentication yes : 公開鍵による認証を有効にする
  • PasswordAuthentication no : パスワードによる認証を無効にする
Move-Item "${Env:ProgramData}\ssh\sshd_config" "${Env:ProgramData}\ssh\sshd_config.original"
$data = "PubkeyAuthentication yes"
$data += "`n" + "PasswordAuthentication no"
Out-File -FilePath "${Env:ProgramData}\ssh\sshd_config" -InputObject $data -Encoding ascii

まず 5 行目で、デフォルトの config ファイルをリネームして退避しています。

6~7 行目でファイルの内容を変数に代入します。(改行を忘れずに)

最後に 8 行目で、設定した変数の内容をファイルに出力します。
-Encoding ascii を付けることで「ASCII 形式」で出力されます。( -Encoding を省略すると「UTF-16」になってしまうので注意してください)

2019/8/5: 初出時に下記のように記述していましたが、誤りがありましたので上記のように訂正いたします。

`-Encoding default` を付けることで、デフォルトのエンコード形式である「UTF-8」で出力されます。(OpenSSH の config ファイル形式は UTF-8 です)
※ なお `-Encoding utf8` とすると「BOM付きUTF-8」になり、 `-Encoding` を省略すると「UTF-16」になってしまうので注意してください。

-Encoding default を指定した時のエンコード形式は、OS のロケールに依存し、例えば英語 (米国) だと「CP437」(DOS Latin US)、日本語だと「CP932」(Shift-JIS MS拡張) になります。
アプリの設定ファイルのように明示的に ASCII 形式で出力したい場合は -Encoding default ではなく -Encoding ascii を指定するのが正しいです。

公開鍵ファイルの配置

前回の記事にも書きましたが、Windows インスタンスの作成時に指定したキーペアの公開鍵を取得するには、インスタンスメタデータへアクセスします。

Amazon EC2 のキーペアと Windows インスタンス -> インスタンスからキーペアのパブリックキーを取得する

New-Item -Path "${Env:USERPROFILE}" -Name ".ssh" -ItemType Directory
Invoke-RestMethod -Uri "http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key" -OutFile "${Env:USERPROFILE}\.ssh\authorized_keys"

9 行目では .ssh フォルダを新規作成しています。

10 行目では、インスタンスメタデータの URL にアクセスしてデータを取得するために Invoke-RestMethod コマンドレットを使っています。
(Linux での curlwget コマンドに相当するコマンドレットです)

OpenSSH Server サービスを再起動して設定を反映

最後に、OpenSSH Server サービスを再起動して設定完了です。

Restart-Service -Name sshd

セキュリティグループの設定について

前項のように UserData の設定を行うことで、Windows インスタンスが起動した時点で「SSH トンネリング経由でのリモートデスクトップ接続」を受け付ける状態になっています。

したがって、対象 Windows インスタンスのセキュリティグループ設定には RDP プロトコルの接続許可 (TCP/3389) は不要であり、SSH プロトコルの接続許可 (TCP/22) のみ設定しておけばよいということになります。

(構築中/運用中にセキュリティグループの設定変更を行わなくてよいというのもメリットの一つかもしれません)

おわりに

Windows サーバー側の事前設定を自動化することによって、より効率的に「リモートデスクトップ接続の SSH トンネリング」の導入が行えるようになったのではないかと思います。