Windows Server に RDP 接続する時にパスワードを調べて入力したくないし文書にも書きたくない

この記事を書いたメンバー:

那須 隆

Windows Server に RDP 接続する時にパスワードを調べて入力したくないし文書にも書きたくない

目次

ウォーキングと懸垂を継続した結果 8kg 痩せました、那須です。
Windows Server に RDP で接続する時、サーバ名や IP アドレス、ユーザ名、パスワードをそれぞれ入力しますよね。 たまにならいいんですが、毎日様々なお客様の環境を運用や構築をしているとログイン情報を毎回確認してから接続する手順で作業を行うことが多いです。 そんな状況でこんな場面はないですか?
・接続先、ユーザ名、パスワードがどこに書かれているか思い出せない
・書かれているところはわかるけどそこにたどり着くまでに時間がかかる
・ログイン情報が書かれたページやドキュメントが誰でも見える場所にある
・そもそも接続情報を手入力したくない
上記をある程度改善できる仕組みというかスクリプトを作成したので、共有します。 2 年前に個人のブログで似たような記事を書いたのですが、今回はそれをちょこっとアップデートした内容になります。


Secrets Manager を使ってパスワードを入力せずに RDP してみた - sorta kinda...

パスワード管理めんどくさいです、那須です。 PrivateLink 経由で Secrets Manager が使えるようになったと AWS から発表がありました。 AWS Secrets Manager Now Supports AWS PrivateLink これ読んで、そういえば Secrets Manager 全くやってなかったな。。。と思ったのでひとまずやってみました。 ただシークレット情報を取り出すだけだと他のブログでたくさん書かれているので、Windows Server に RDP するためのパスワードをシークレット情報として登録して、それを PowerShell から取り出して …

nasrinjp1.hatenablog.com

og_img

仕組みの構成

以下の通り、めちゃくちゃシンプルです。

前提作業

以下 2 点の前提があります。
・RDP 接続したいインスタンスに Name タグが設定されていること
・ユーザ名とパスワードが AWS Systems Manager Parameter Store (以下、SSM Parameter Store) に登録されていること
ほとんどの環境で Name タグは設定されていると思いますのでここでの説明は割愛します。
SSM Parameter Store にユーザ名やパスワード(以下、クレデンシャル情報)を入れるには、以下のドキュメントが参考になります。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/what-is-systems-manager.html

SSM Paramerer Store にクレデンシャル情報を入れるコマンド例は以下です。 パラメータ名の最初の /credentials/ は固定で、その後 AD ユーザであれば ad/domain/username 、ローカルユーザであれば local/username のように指定します。
あくまで一例なので、全然違う名前や階層で登録しても OK です。 その場合はあとで紹介するスクリプトのパラメータ名の指定部分も変更して使ってください。

 Write-SSMParameter`
    -Name "/credentials/ad/domain/username" `
    -Value "naisyonopassword" `
    -Type "SecureString" `
    -KeyID "alias/aliasname"

タイプは SecureString で保存することが最重要ポイントです! String で保存してしまうと誰でも見れる状態になってしまいますよ!
これで準備 OK です。

スクリプトと使い方

実行するスクリプトの内容は以下の通りです。 SSM Parameter Store のパラメータ名の指定部分や接続先の指定の方法は固定して書いていますが、自由に決められますので適宜修正してください。

 param(
    [string]$ServerName,
    [string]$User,
    [string]$ProfileName,
    [string]$Token
)
 
$ErrorActionPreference "Stop"
 
# Generate the parameter name
## For AD users
if ($User -match "\\") {
    $ssm_cred_name "/credentials/ad/" + ($User -replace "\\""/")
}
## For local users
else {
    $ssm_cred_name "/credentials/local/" $ServerName "/" $User
}
$ssm_ip_name "/ip-address/" $ServerName
 
# Get the target information
$targetrole Get-AWSCredential -ProfileName $ProfileName
$role Use-STSRole -RoleArn $targetrole.RoleArn -RoleSessionName $targetrole.RoleSessionName -SerialNumber $targetrole.Options.MfaSerialNumber -TokenCode $Token
 
$password = (Get-SSMParameterValue -Name $ssm_cred_name -WithDecryption $true -Credential $role.Credentials).Parameters.Value
$server_ip = (Get-SSMParameterValue -Name $ssm_ip_name -Credential $role.Credentials).Parameters.Value
 
# Connect to the target
cmdkey /generic:TERMSRV/$server_ip /user:$User /pass:$password
mstsc /v:$server_ip

すぐ手元に取ってこれるよう、Github にも公開しています。


GitHub - nasrinjp/ec2-connect

Contribute to nasrinjp/ec2-connect development by creating an account on GitHub.

github.com

og_img

スクリプトを実行するためには、AWS Tools for PowerShell Version 4 がインストールされている必要があります。テストしたのが Version 4 だっただけなので、Version 4 じゃなくてもいいと思います。
動きとしては単純で、プライベート IP アドレスとパスワードを SSM Parameter Store から取得して、収集した情報を使って mstsc を実行しているだけです。
このスクリプトを実行すると、

 > .\rdp-connect.ps1 -ServerName hostname -User domain\user -ProfileName test -Token 123456 
CMDKEY: 資格情報を正しく追加しました。

のように PowerShell ウィンドウで表示された後、RDP ウィンドウが開いて自動で接続してくれます。

SSM Parameter Store に保存してもクレデンシャル情報を見られるのでは?

クレデンシャル情報の保存場所が違うだけで結局誰にでも見られるのでは?と疑問をもった方もいるかもしれませんが、SSM Parameter Store を保存場所にしたのはちゃんと理由があります。 AWS マネジメントコンソールにログインできる人でも、クレデンシャル情報の暗号に使った KMS CMK で復号ができる権限を持っていなければクレデンシャル情報を見られることはありません。 KMS CMK のキーポリシーで、例えば以下のような内容を追記するだけで nasu ユーザはクレデンシャル情報にアクセスできなくなります。

 {
    "Effect": "Deny",
    "Principal": {
        "AWS": "arn:aws:iam::111111111111:user/nasu"
    },
    "Action": "kms:Decrypt",
    "Resource": "*"
}

上記のポリシーが設定されている状況で nasu ユーザがこのスクリプトを使うと、以下のようなエラーになって Windows Server にアクセスできません。 クレデンシャル情報を知ることができないので、これで RDP アクセスできてはいけない人が RDP アクセスを試行してもそれを拒否することができましたね。

 > .\rdp-connect.ps1 -NameTag hostname -User domain\user -Profilename test
Get-SSMParameterValue : The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access. (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: 790a6db3-bb2f-48ec-821d-joefjaofe; Proxy: null)
発生場所 C:\work\rdp-connect.ps1:16 文字:14
+ ... password = (Get-SSMParameterValue -Name $ssm_param_name -WithDecrypti ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Amazon.PowerShe...eterValueCmdlet:GetSSMParameterValueCmdlet) [Get-SSMParameterValue]、InvalidOperationException
    + FullyQualifiedErrorId : Amazon.SimpleSystemsManagement.AmazonSimpleSystemsManagementException,Amazon.PowerShell.Cmdlets.SSM.GetSSMParameterValueCmdlet

これを作った背景

タイトルの通りなんですが、毎回手入力してるとそれだけで時間かかりますしクレデンシャル情報を見つけるまでの時間もかかってしまいますので、その時間を減らしたかったのが主な理由です。 また、ドキュメントや Wiki 等でクレデンシャル情報をまとめて管理していると、アクセス制御があるべき姿ではない場合に簡単にクレデンシャル情報を持ち出されてしまいます。 そのクレデンシャル情報が個人を特定するものではなく共有の情報だったら誰でも使える状況になる可能性もありますよね。 ですので、人間の目に触れる場所に書かない、かつ手入力させる状況を作らない、そしてそのクレデンシャル情報を必要とする人のみが見れる状況にすることが大事なのではないかと考えてこの記事を書きました。
あとは、パスワードを更新しても関係者に周知する必要がないのも大きなメリットかなと思います。スクリプトが都度最新のクレデンシャル情報を確認するので人が知る必要がないですよね。

さいごに

今回のようなスクリプトを使うだけである程度セキュアな状態でクレデンシャル情報を管理できることがわかったので、個人的には使っていこうと思いました。環境ごとに接続対象インスタンスの条件キーやクレデンシャル情報の保存場所のルールみたいなものが異なるとは思うのでこれ 1 つで完璧!というものではないですが、あるのとないのとでは全然違うので少しずつ汎用的に使えるように更新してみようと思います。

カテゴリー
タグ

SAPシステムや基幹システムのクラウド移行・構築・保守、
DXに関して
お気軽にご相談ください

03-6260-6240 (受付時間 平日9:30〜18:00)