注意
自己責任でお願いします。これら記事の内容を実行して何か不都合を被ったとしても筆者は責任を負いません。
性質上セキュリティホールを自分で開けているようなものなので、実装は実験目的かつ仮想環境を推奨します。また当たり前ですが実装自体には管理者権限が必要です。また自分の所有する端末のみで行ってください。
もし sudo を使いたいなら、Windows 標準 か Grignoli 氏の gsudo を使えばよいと思います。
構成
目次
1. 変数の宣言と代入
2. 接続設定
3. 構成ファイル作成・登録
4. 権限設定
5. 証明書作成
6. 証明書紐付け
7. 実行・関数作成
8. 後始末
説明
WinRM と各証明書およびユーザーの紐付けを行います。証明書マッピングのところでクライアント側の NTLM ユーザー認証(New Technology LAN Manager)が行われます。
注意点として、
- HTTPS リスナーの
Hostnameにはサーバー証明書のSubjectに設定した値と同じものを指定すること - 証明書マッピングの
Subjectにはユーザーアカウントの UPN 表記を指定すること - 同
UserNameにはプレフィックス無しのユーザー名を指定すること
があります。
内容
使用する変数:
$HostName $RegLmPath $WsManPath $WinRmPath $LocateUser $LocateMy $LocateCA $UserName $LocalUPN $Password
$HostName = "127.0.0.1"
$RegLmPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN"
$WsManPath = "WSMan:\localhost"
$WinRmPath = "winrm/config"
$LocateUser = "Cert:\CurrentUser\My"
$LocateMy = "Cert:\LocalMachine\My"
$LocateCA = "Cert:\LocalMachine\CA"
$SelectUser = [Security.Principal.WindowsIdentity]::GetCurrent().Name
$UserObject = [Security.Principal.NTAccount]::new($SelectUser)
$UserName = $UserObject.Value.Split("\")[-1]
$LocalUPN = "$UserName@localhost"
$LogonName = (Get-CimInstance Win32_UserAccount).Where{$_.Name -eq $UserName}[0].Caption
$Credential = Get-Credential $LogonName
$Password = $Credential.GetNetworkCredential().Password
↓すべて管理者権限で実行します↓
# 既存の構成を削除
Get-ChildItem WSMan:\localhost\Listener | Remove-Item -Recurse -Force
# ローカル専用 HTTP リスナー作成
New-Item $WsManPath\Listener -Force -Address "IP:127.0.0.1" -Transport HTTP
# サーバー証明書から拇印を取得
$ServerCert = (Get-ChildItem $LocateMy).Where{$_.FriendlyName -like "My Server Cert - UserDef"}[-1]
# 設定を追加するリスナーを選択
$SelectorSet = @{
Address = "IP:127.0.0.1"
Transport = "HTTPS"
}
# 設定内容
$ValueSet = @{
Enabled = 1
Hostname = $HostName
CertificateThumbprint = $ServerCert.Thumbprint
}
# 反映
New-WSManInstance -ResourceURI $WinRmPath/Listener -SelectorSet $SelectorSet -ValueSet $ValueSet
# 証明書認証を有効化
Set-Item $WsManPath\Service\Auth\Certificate -Value $true -Force
# 既存の構成を削除
Remove-Item $RegLmPath\CertMapping\* -WhatIf
# 中間証明書の拇印を取得
$InterCert = (Get-ChildItem $LocateCA).Where{$_.FriendlyName -like "My Intermediate CA - UserDef"}
# 「認証を許可するユーザー」・「その認証を検証する証明書の拇印」 をセットで追加する
$SelectorSet = @{
Subject = $LocalUPN
Issuer = $InterCert.Thumbprint
URI = "*"
}
# このタイミングで、ユーザ名とパスワードを使って NTLM 認証
$ValueSet = @{
UserName = $UserName
Password = $Password
}
New-WSManInstance -ResourceURI $WinRmPath/service/certmapping -SelectorSet $SelectorSet -ValueSet $ValueSet
# WinRM 更新・再起動
Restart-Service WinRM -Force
# 確認
Get-WSManInstance $WinRmPath/listener -Enumerate
Get-ChildItem $WsManPath\Service\Auth
Get-ChildItem $RegLmPath\CertMapping
# クライアント証明書から拇印を取得
$ClientCert = (Get-ChildItem $LocateUser).Where{$_.FriendlyName -like "My Client Cert - UserDef"}[-1]
# 接続試行
Test-WSMan -UseSSL `
-ComputerName 127.0.0.1 `
-Authentication ClientCertificate `
-CertificateThumbprint $ClientCert.Thumbprint
# 失敗する場合(Windows Sandbox 固有)
<#
WS-Management サービスは操作を処理できません。
マップされている資格情報の照会が失敗しました。
これは、資格情報が最初にマップされてから以降に、
WinRM サービスに関連付けられているセキュリティコンテキストが変更された場合に発生します。
#>
# と出た場合は、このページ(4. 証明書紐付け)を最初からすべてやり直す。