SSHを使用したPowerShellの例
Windowsサービスの「Log on as」認証情報を更新するためのPAMスクリプト
このセットアップには、PowerShell 7とOpenSSHが必要です。Keeperゲートウェイホストシステムおよび対象のWindowsベースシステムにPowerShell 7をインストールしていない場合は、「Windows上のPowerShell 7」と「Windows上のOpenSSH」の手順をご確認ください。
概要
以下のPowerShellコード例では、PowerShell 7を使用して確立したSSHセッションにおいてKeeper ローテーションでパスワードをローテーションした後、Windowsサービスの「Log on as」認証情報を更新します。
例
この例では、確立された「SSH」セッションを介してWindowsベースのターゲットシステムに対して「Invoke-Method」を使用し、サービスの管理にはPowerShell 7のネイティブコマンドレットを使用します。この場合、「Microsoft.PowerShell.Management」とそのサブコマンド (「Get-Service」や「Set-Service」など) を使用して、ターゲットWindowsサービスの「Log on as」認証情報を管理します。
手順 1
以下のPowerShellスクリプトを開いてコピーし、任意のファイル名で「.ps1」として保存します。この例では、スクリプトのファイル名を「rotate_service_cred.ps1
」としました。このスクリプトをPAMユーザーレコードの「PAMスクリプト」セクションに添付します。
さらに、現在のPAMユーザーレコードを選択して、「ローテーションクレデンシャル」レコードを1つ含めます。「コマンドプレフィックスで実行」のチェックボックスをオンにし、PowerShell 7の実行ファイルのパスを指定してください (必須)。
Invoke-Command
を使用したPowerShellスクリプト (SSHを利用)
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
[string]
$Record
)
try {
# このセクションでは、PAMユーザーレコード情報を取得しますn
Write-Debug "Decoding and converting the PAM User Record Information from Base64"
$RecordJsonAsB64 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Record))
if (-not $RecordJsonAsB64) {
throw "Failed to decode the PAM User Record Information from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$RecordParams = $RecordJsonAsB64 | ConvertFrom-Json
if (-not $RecordParams) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "PAM User Record Information successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the PAM User Record Information: $_"
}
finally {
Write-Debug "Completed processing the PAM User Record Information."
}
# セクションの終了
try {
# このセクションでは、すべての関連レコードとそのパラメーター情報を取り込みます。
Write-Debug "Decoding and converting all associated records from Base64"
$recordsJSON = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($RecordParams.records))
if (-not $recordsJSON) {
throw "Failed to decode the associated records from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$records = $recordsJSON | ConvertFrom-Json
if (-not $records) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "Associated records successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the associated records: $_"
}
finally {
Write-Debug "Completed processing the associated records."
}
# セクションの終了
try {
# このセクションでは、ユーザーレコードからパラメーターを定義します。「remotecomp」と「service」は、PAMユーザーレコードのカスタムフィールドから取得されます。
Write-Debug "Defining parameters from the User Record"
$ErrorActionPreference = 'Stop'
$DebugPreference = 'Continue'
$remoteComputer = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).remotecomp
if (-not $remoteComputer) {
throw "Failed to retrieve 'remotecomp' from the User Record."
}
$serviceName = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).service
if (-not $serviceName) {
throw "Failed to retrieve 'service' from the User Record."
}
$user = ($RecordParams.user)
if (-not $user) {
throw "Failed to retrieve 'user' from the User Record."
}
$newPassword = ($RecordParams.newPassword)
if (-not $newPassword) {
throw "Failed to retrieve 'newPassword' from the User Record."
}
Write-Debug "Parameters from the User Record successfully defined."
}
catch {
Write-Error "An error occurred while defining parameters from the User Record: $_"
}
finally {
Write-Debug "Completed defining parameters from the User Record."
}
# セクションの終了
try {
# このセクションでは、AD管理リソースレコードを使用して新しいPSSessionを作成します
Write-Debug "Creating a new SSH Session with the AD Administrative Resource Record"
$session = New-PSSession -HostName $remoteComputer -UserName $user -ErrorAction Stop
if (-not $session) {
throw "Failed to create a new SSH Session."
}
Write-Debug "SSH Session created successfully."
}
catch {
Write-Error "An error occurred while creating the SSH Session: $_"
}
finally {
Write-Debug "Completed the attempt to create a new SSH Session."
}
# セクションの終了
try {
# このスクリプトブロックはリモートコンピューター上のサービスの状態を確認します
Write-Debug "Checking the status of $serviceName"
$serviceStatus = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
$service = Get-Service -Name $serviceName -ErrorAction Stop
return $service.Status
}
catch {
throw "An error occurred while retrieving the service status: $_"
}
} -ArgumentList $serviceName
if ($serviceStatus -eq 'Stopped') {
Write-Debug "$serviceName is already stopped. Skipping the stop service script."
}
else {
try {
# このスクリプトブロックはリモートコンピューター上のサービスを停止します
Write-Debug "Stopping $serviceName"
$stopServiceResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
Stop-Service -Name $serviceName -Force -ErrorAction Stop
$service = Get-Service -Name $serviceName
if ($service.Status -ne 'Stopped') {
throw "Service did not stop successfully. Current status: $($service.Status)"
}
Write-Output "Service stopped successfully"
}
catch {
throw "An error occurred while stopping the service: $_"
}
} -ArgumentList $serviceName
if ($stopServiceResult -ne "Service stopped successfully") {
throw "Service stop operation did not return success."
}
}
catch {
Write-Error "An error occurred while stopping the service: $_"
}
}
}
catch {
Write-Error "An error occurred while checking or stopping the service: $_"
}
finally {
Write-Debug "Completed checking and stopping the service."
}
try {
# このスクリプトブロックはリモートコンピューター上のサービスのパスワードを更新します
Write-Debug "Changing $serviceName password"
$passwordChangeResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName, $user, $newPassword)
try {
$service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$serviceName'" -ErrorAction Stop
$result = Invoke-CimMethod -InputObject $service -MethodName Change -Arguments @{StartName=$user; StartPassword=$newPassword}
if ($result.ReturnValue -eq 0) {
Write-Output "Password changed successfully"
}
else {
throw "Failed to change password with return value $($result.ReturnValue)"
}
}
catch {
throw "An error occurred while changing the service password: $_"
}
} -ArgumentList $serviceName, $user, $newPassword
if ($passwordChangeResult -ne "Password changed successfully") {
throw "Password change operation did not return success."
}
}
catch {
Write-Error "An error occurred while changing the service password: $_"
}
finally {
Write-Debug "Completed changing the service password."
}
try {
# このスクリプトブロックはリモートコンピューター上でサービスを開始します
Write-Debug "Restarting $serviceName"
$startServiceResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
Start-Service -Name $serviceName -ErrorAction Stop
$service = Get-Service -Name $serviceName
if ($service.Status -ne 'Running') {
throw "Service did not start successfully. Current status: $($service.Status)"
}
Write-Output "Service started successfully"
}
catch {
throw "An error occurred while starting the service: $_"
}
} -ArgumentList $serviceName
if ($startServiceResult -ne "Service started successfully") {
throw "Service start operation did not return success."
}
}
catch {
Write-Error "An error occurred while restarting the service: $_"
}
finally {
Write-Debug "Completed attempting to restart the service."
}
# スクリプトブロックの終了.
# このセクションでは、SSHセッションを削除します。
Remove-PSSession -Session $session
# セクションの終了on
以下は結果として得られるPAMスクリプト設定画面です。
手順 2
PAMユーザーレコードに「remotecomp
」と「service
」という2つのカスタムテキストフィールドを追加します。「remotecomp
」フィールドには、サービスを実行しているターゲットシステムのDNS名を入力します。この例では、「EC2AMAZ-A0GBNDM」がターゲットシステムの名前となります。管理しているWindowsサービスがKeeperゲートウェイホストに対してローカルである場合は、「remotecomp
」フィールドに「localhost」を使用します。「service
」フィールドには、サービスの「Service Name」を入力します (「Display Name」ではありません)。この例では、「Service Name」は「SNMPTRAP」となります。
以下は、結果として得られるボルト内のレコード設定となります。
スクリプトの実行
手順に従うと、Keeperのパスワードローテーションと同様に、[ローテーションする]ボタンを使用して、スクリプトを「オンデマンド」で実行してテストできます。また、「パスワードローテーション設定」でスクリプトのスケジュールを設定することもできます。