見出し画像

WinRMイシュー:リモートのリモート(ダブルホップ)問題と解決

はじめに

こんにちは、DevOpsエンジニアのユです。
前回はWindowsのリモート経験より、WinRMを使ってWindowsを遠隔操作してみたブログを書きました。
この文章は前回のノウハウを基づいて作りましたので、「WinRMって何?」の方は、先にそちらを読んでください。

今回は、筆者がWinRMを利用したスクリプト開発の途中に発生したイシュー、リモートのリモート(ダブルホップ)問題ではまってしまった経験より、問題と解決方法を共有したいと思います。

ダブルホップって何?

WinRMでリモートする際にもう一回リモートすることはダブルホップ(double hop)と言われます(「次ホップ」second hop と称する場合もあります)。

2番目のホストにユーザーの資格情報を渡すことができないので、2番目のホストではユーザーがNT AUTHORITY\ANONYMOUS LOGONになってしまって、特定なユーザー権限が必要の時にイシューが発生しまいます。

# 二番目ホスト(Windowsサーバー)にあるデータベースへアクセスする時に発生したエラー
ユーザー 'NT AUTHORITY\ANONYMOUS LOGON' はログインできませんでした。

上記のようなエラーになります。
問題というより、セキュリティー性を確保する仕組みですので、Microsoft社に認識されていくつの解決方法が提供されました。今回は実際に使用した方法(CredSSP)のみ詳細説明しますが、他の方法もリストアップしておきます。

ダブルホップより生じた資格情報渡し問題の解決

PowerShellリモート処理での次ホップの実行

Microsoftオフィシャルドキュメントより、「次ホップ」(second hop)問題の解決はいくつの方法があります。

  • CredSSP

  • Kerberosの リソースに基づく制約付き/制約付き/無制限 委任

  • Just Enough Administration (JEA)

  • RunAs を使用する PSSessionConfiguration

  • Invoke-Command スクリプトブロックの内部で資格情報を渡す

詳細はオフィシャルドキュメント「PowerShell リモート処理での次ホップの実行」を参照してください。

上記のすべての方法がダブルホップ問題を対応できますが、今回はセキュリティ性と利便性のバランスがいい、Microsoftが推奨する方法CredSSPを説明します。

CredSSP基本紹介

Credential Security Support Provider (CredSSP) は、Security Support Provider Interface (SSPI) を使用して実装されるセキュリティサポートプロバイダーです。 CredSSP を使用すると、ロカール(リモート元、以降クライアントと呼ぶ)にあるアプリケーションはリモート認証のためにユーザーの資格情報をクライアントからターゲットサーバー(リモート先、以降ホストと呼ぶ)に委任できます。(制約付き委任ではありません。ユーザーの完全な資格情報を制約なくホストに渡しますので気をつけてください。)
クライアントは Microsoft Kerberos または Microsoft NTLM のいずれかで Simple and Protected Negotiate (SPNEGO) プロトコルを使用して、暗号化されたチャネル経由で認証されます。

以上はCredSSPのドキュメントから抜粋して少し説明を入れた紹介です。詳細はドキュメントを参照してください。

準備

WinRMの使用には前提があります。前回のブログにWinRM使用前提や起動と設定の仕方が記述されているので、参考にしてください。
WinRMの起動と設定が完了したら、以下のステップを追加します。

  • CredSSP起動(ホスト)
    ホストのPowerShellで以下のコマンドを打って、対話にYを入力します。

PS C:\Windows\system32> Enable-WSManCredSSP -Role Server
  • CredSSP起動(クライアント)
    クライアントのPowerShellで以下のコマンドを打って、対話にYを入力します。
    ※ $serversがホストのIPもしくはドメイン上のコンピューター名両方大丈夫です。

PS C:\Windows\system32> $servers = "xx.xx.xx.xx", "xx.xx.xx.xxx"
PS C:\Windows\system32> Enable-WSManCredSSP -Role "Client" -DelegateComputer $servers
  • CredSSP状態確認(ホストとクライアント)
    確認用。「構成されているか、アカウント情報をどのホストに送るのが可能か」情報を取得できます。

PS C:\Windows\system32> Get-WSManCredSSP

資格情報を NTLM 認証で行う様にグループポリシーを設定
この記事の「リモートを呼び出す側で、資格情報を NTLM 認証で行う様にグループポリシーを設定」を従って行います

CredSSP状態確認(ホストとクライアント)
確認用。「構成されているか、アカウント情報をどのホストに送るのが可能か」情報を取得できます。

PS C:\Windows\system32> Get-WSManCredSSP
  • 資格情報を NTLM 認証で行う様にグループポリシーを設定
    この記事の「リモートを呼び出す側で、資格情報を NTLM 認証で行う様にグループポリシーを設定」を従って行います

    • gpedit.msc コマンド:Win10の検索にgpeditを入力して「グループポリシーの編集」を起動する

    • サーバーを一覧に追加: 「表示」ボタンをクリックするとログイン情報を渡す対象ホストを追加できる

    • wsman/リモートコンピュータ名・IP: リモートしたいホストを一つ一つwsman/xx.xx.xx.xx で追加すること

    • 追加して適用とOKをクリックすれば完了

手動操作

殆ど前回の「手動操作」セクションに紹介されたスクリプトと同じですが、"セッションでリモートアクセス"する時に-Authenticationを追加してCredSSP方法を指定します。

  • 非対話型認証を作成

# useraccount=ユーザーアカウント名、userpassword=ユーザーパスワード
$password = ConvertTo-SecureString "userpassword" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("DOMAIN\useraccount", $password)
  • セッションでリモートアクセス
    IPがxx.xx.xx.xxのホストへアクセスします。
    ※上記で作成した認証用の変数$cardを使います。

$remoteHost = "xx.xx.xx.xx"
Enter-PSSession -ComputerName $remoteHost -Credential $cred -Authentication CredSSP
  • 直接操作
    これでホストのPowerShellをリモートで直接操作
    できるようになりました。

# リモートでWFE2のPS操作
  [xx.xx.xx.xx]: PS C:\Users\spadmin\Documents> $Env:ComputerName
  ホストコンピューター名

  # セッション切断
  [xx.xx.xx.xx]: PS C:\Users\spadmin\Documents> Exit-PSSession

スクリプトをリモート実行

殆ど前回の「スクリプトをリモート実行」セクションと同じですが、WinRMを行うスクリプトのPSセッションを作成に-Authenticationを追加してCredSSP方法を指定します。

# WinRM起動、信頼できるホストをリスト追加、CredSSP起動済み

# HOSTにログイン用パスワード設定:useraccount=ユーザーアカウント名、userpassword=ユーザーパスワード
$password = ConvertTo-SecureString "userpassword" -AsPlainText -Force
# 非対話型認証作成
$cred = New-Object System.Management.Automation.PSCredential ("DOMAIN\useraccount", $password)
# リモート対象設定(信頼できるホストリストにある登録ホストと一致する値を設定)
$remoteHost = "HOST"
# PSセッションを作成(ダブルホップ)
$session = New-PSSession -ComputerName $remoteHost -Credential $cred -Authentication CredSSP
# クライアント(ローカル側)にある、リモートで実行したいPSスクリプトのパス
$localps = "C:\work\remote_script_utf8.ps1"

# リモートでローカルのPSを実行して結果を出力される
Invoke-Command -Session $session -FilePath $localps

まとめ

今回のイシューは、筆者がPowerShell初心者なのにドキュメントを読まずにハマった問題です。自業自得です。おかげで(?)Windowsのリモート仕組みをより深く理解できました。

イシュー解決した後の感想ですが、ダブルホップに関して色んな要素を考慮する必要がありますし、「一番な解決方法」がありません。今回はインフラを気にする必要がないという前提で便利性やセキュリティ性だけを考慮しましたが、実際使う時にやっぱり環境(権限情報の保存、ドメイン、管理者権限、リモート先設定…)などを総合的に考えなければなりません。

その理由でMicrosoftが提供する解決方法をリストアップしましたので、ご参考になれば幸いです。


執筆者プロフィール:ユ ツォンウェン
最近実験してること:スクラムを応用して自己管理する。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/