Windows Server EC2の管理者パスワードについて調べてみた

しばたです。
基本的なことですが大事なことなので本記事を書きます。

Windows Server EC2の管理者パスワード

EC2ConfigEC2Launchの設定でパスワードを明示しない限り、Windows Server EC2では管理者ユーザー(Administrator)のパスワードはインスタンス作成時にランダムな値が生成されます。
このランダムなパスワードはマネジメントコンソールからEC2キーペアを使うことで参照することができます。

ちなみにコマンドからだとaws ec2 get-password-dataGet-EC2PasswordDataを使って取得することもできます。

# Get-EC2PasswordDataを使ったパスワード取得の例
Get-EC2PasswordData -InstanceId '[対象インスタンスID]' -Decrypt -PemFile '[PEMファイルのパス].pem'

Windowsのログオン認証とEC2キーペア

Windowsの対話ログオンではスマートカードを使用する場合以外は鍵交換による認証はありません。
EC2キーペアを使う部分に関してはAWSが提供する機能となります。

少し細かい話をすると、管理者ユーザーのパスワードはEC2ConfigやEC2Launchの初期化処理の最中に生成および設定され、インスタンスメタデータからキーペアの公開鍵を取得、パスワードを暗号化してマネジメントコンソールに送信して永続化という手順を踏んでいます。

パスワード変更時の注意点

この様にEC2インスタンスの"初期化処理"でパスワード情報が設定されるため、インスタンス起動後に管理者ユーザーのパスワードを変更してもその変更はマネジメントコンソールには反映されません。

これはドキュメントにもきっちり記載されています。

重要
新しいパスワードを安全な場所に保存します。Amazon EC2 コンソールを使用して新しいパスワードを取得することはできません。
コンソールでは、デフォルトのパスワードのみ取得できます。

変更したあとのパスワードを忘れてしまうとEC2インスタンスのパスワードリセットをするしかありませんので気をつけてください。

【補足】変更したパスワードをマネジメントコンソールに反映できないのか?

先述の通り管理者パスワードは初期登録時のみマネジメントコンソールに記録されるのですが、EC2ConfigやEC2Launchでそれを行っているのなら「新しいパスワードをマネジメントコンソールに反映する機能も提供されているのでは?」と思い調べてみました。

EC2Launchの方が実装を調べやすかったためWindows Server 2016が調査対象です。
EC2Configは調べていません。

公式な手順

結論から先に書くと変更したパスワードをマネジメントコンソールに反映させる手段は 公式には提供されていません でした。

ただし、EC2Launchで公開されている内部処理を調べてパスワードをマネジメントコンソールに通知していると思しき機能を発見し、その機能を使うことで変更したパスワードをマネジメントコンソールに反映させることはできました。
本記事は軽くこの内部処理の解説をして終わりにしたいと思います。

免責事項



ここから先の内容は私が個人で調べた結果を記載しているだけであり公に保証されるものは一切ありません。

無保証であり、記述されているコードを実環境で実施した際に何が起きても責任は負えませんのでご注意ください。
紹介する機能はEC2Launchで公開されているものですので使うこと自体に問題は無いはずですが無保証であることは重ねてお伝えしておきます。

EC2Launchにおけるパスワード設定

EC2LaunchにはSet-AdminAccountという関数があり、この処理の中で管理者ユーザーに対してパスワードを設定しています。
主要な部分を以下に抜粋しますがSIDから管理者ユーザーを検索しnet userコマンドでパスワードを更新しています。
(ランダムパスワードを生成する部分はまた別の処理)

# Set-AdminAccount関数の処理を一部抜粋

# Finally, the password is ready to be set.
$user = Get-CimInstance -ClassName Win32_UserAccount -Filter "LocalAccount = 'True'" | Where-Object {$_.SID -like 'S-1-5-21-*' -and $_.SID -like '*-500'}

# Set the admin password and enable the admin account.
net user $user.Name $password /ACTIVE:YES /LOGONPASSWORDCHG:NO /EXPIRES:NEVER /PASSWORDREQ:YES

やっていることはWindowsにおけるごく普通のパスワード設定であり、特別なことはありませんでした。

EC2Launchにおけるパスワード通知

では設定したパスワードをどこでマネジメントコンソールに送っているかというと、Send-AdminCredentials関数で送っている様です。
この関数はUsernamePassword(平文)の2つの引数を取り、パスワードを暗号化してマネジメントコンソールに送信しています。

マネジメントコンソールに情報を送るにはログおよびシリアルポートの初期化がされていることが前提の様で、以下の様な処理が最低限Send-AdminCredentialsを動作させるのに必要な様です。

#
# EC2Launchの実装を参考に最低限動作する"ハズ"のSend-AdminCredentials
# ※ この処理の動作に関しては無保証ですのでご注意ください ※
#

$username = (Get-CimInstance -ClassName Win32_UserAccount -Filter "LocalAccount = 'True'" | Where-Object {$_.SID -like 'S-1-5-21-*' -and $_.SID -like '*-500'}).Name
$password = 'P@ssw0rd-123456789'

Import-Module (Join-Path $env:ProgramData 'Amazon\EC2-Windows\Launch\Module\Ec2Launch.psd1')
try {
    Initialize-Log -Filename "ChangePassword.log" -AllowLogToConsole
    Open-SerialPort
    Set-SerialPort
    Send-AdminCredentials -Username $username -Password $password
} finally {
    Close-SerialPort
    Complete-Log
}

管理者ユーザーのパスワードを設定後にこのSend-AdminCredentialsを実行すると下図の様にマネジメントコンソールに変更を反映させることができました。
(OSの再起動が必要だったり不要だったりします...)

くどい様ですがこの処理を実環境で実行することは推奨できませんし無保証ですのでご注意ください。