SSHを使用したPowerShellの例

Windowsサービスの「Log on as」認証情報を更新するためのPAMスクリプト

このスクリプトを実行するには、Keeperゲートウェイホストシステムと対象システム間でSSH鍵ベースの認証を設定し、有効化する必要があります。鍵ペア認証をまだ設定していない場合は、以下のURLをご確認ください。

概要

以下の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」となります。

以下は、結果として得られるボルト内のレコード設定となります。

PAMユーザーレコード

スクリプトの実行

手順に従うと、Keeperのパスワードローテーションと同様に、[ローテーションする]ボタンを使用して、スクリプトを「オンデマンド」で実行してテストできます。また、「パスワードローテーション設定」でスクリプトのスケジュールを設定することもできます。

最終更新