目次
ウォーキングと懸垂を継続した結果 8kg 痩せました、那須です。
Windows Server に RDP で接続する時、サーバ名や IP アドレス、ユーザ名、パスワードをそれぞれ入力しますよね。 たまにならいいんですが、毎日様々なお客様の環境を運用や構築をしているとログイン情報を毎回確認してから接続する手順で作業を行うことが多いです。 そんな状況でこんな場面はないですか?
・接続先、ユーザ名、パスワードがどこに書かれているか思い出せない
・書かれているところはわかるけどそこにたどり着くまでに時間がかかる
・ログイン情報が書かれたページやドキュメントが誰でも見える場所にある
・そもそも接続情報を手入力したくない
上記をある程度改善できる仕組みというかスクリプトを作成したので、共有します。 2 年前に個人のブログで似たような記事を書いたのですが、今回はそれをちょこっとアップデートした内容になります。
仕組みの構成
以下の通り、めちゃくちゃシンプルです。
前提作業
以下 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 にも公開しています。
スクリプトを実行するためには、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 つで完璧!というものではないですが、あるのとないのとでは全然違うので少しずつ汎用的に使えるように更新してみようと思います。
- カテゴリー