Creating a Custom BYOV Connector to Check Out Service Accounts from Privilege Secure
Overview
This article describes how to create a custom BYOV connector so that Netwrix Privilege Secure for Access Management can check out service accounts with the "Internal" managed type. By design, the standard BYOV connector for checking out credentials from Privilege Secure does not allow service accounts with the "Internal" managed type to be checked out. If this functionality is business-critical, this article provides a means for "Internal" type service accounts to be checked out using a BYOV connector.
NOTE: Because service accounts are by nature critical, Netwrix advises that the day-to-day use of these accounts for Privilege Secure sessions be minimized.
NOTE: This connector does not rotate the account's password during the checkout script. Optional instructions are included that rotate the password during the checkin.
Instructions
Before You Begin
Ensure that the account you want to check out is configured in Privilege Secure as a Service Account (Configuration > Service Account), and that the correct password is stored.
Checkout Instructions
-
In the Privilege Secure console, go to the Configuration menu, and then the Integration Connectors submenu.
-
Click the green plus icon to add a new Activity Connector.
-
Configure it according to the following table:
Field Value Name <Anything>Description <Anything>Connector Template BYOV API URL https://localhost:6500App Id SbPAMClient Certificate xSkip Certificate Check True -
Copy and paste the following script into the Checkout Script Block field.
param ($Options,$Credential)$Token = $Options.RestApiToken$Uri = $Options.RestApiUri###### Allow service accounts to be checked out## NOTE This is not recommended.## Service accounts should not be used for interactive logins####$InsecureAllowServiceAccounts = $falsefunction Get-CredentialMatch {[CmdletBinding()]param ($CredentialAccount,$CredentialResource,$Token,$Uri,$CredentialType = 1)$credentials = @()$skip = 0$take = 100$result = $nullif ($null -ne $CredentialAccount) {$FilterText = "$($CredentialAccount)"$Message = "FILTERTEXT: $FilterText"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"do {$Params = @{RestApiToken = $Token;Uri = "$($Uri.TrimEnd("/"))/api/v1/Credential/Search?skip=$skip&take=$take&filterText=$FilterText&credentialType=$CredentialType";}$result = Invoke-SbPAMRest @Params<#$Message = (ConvertTo-Json $result)Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"#>$result.Data | ForEach-Object { $credentials += $_ }$skip += $take} until ($credentials.Count -ge $result.RecordsTotal)$credentials | Foreach-Object {$Message = "FOUND: $($_.Id) UserName: '$($_.UserName)' Resource: '$($_.Domain)'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"}$Message = "Find UserName -eq '$CredentialAccount' -and Resource -eq '$CredentialResource'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"if ($null -ne $CredentialResource) {$result = $credentials | Where-Object { $_.Username -eq $CredentialAccount -and $_.Domain -eq $CredentialResource }}else {$result = $credentials | Where-Object { $_.Username -eq $CredentialAccount }}if ($null -eq $result) {# Try RESOURCE\USERNAME$Test = "$CredentialResource\$CredentialAccount"$Message = "Find UserName -eq '$Test'"$result = $credentials | Where-Object -Property UserName -eq $Test}if ($null -eq $result) {$Test = "$($Options.TargetHost.DnsHostName)\$CredentialAccount"if ($null -ne $Options.TargetHost.NetBiosName) {$Test = "$($Options.TargetHost.NetBiosName)\$CredentialAccount"}$Message = "Find UserName -eq $Test"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"$result = $credentials | Where-Object -Property UserName -eq $Test}else {$Message = "FOUND Username: '$($result.Username)' Resource: '$($result.Domain)'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"}}if ($result.Count -gt 1) {$Message = "Multiple matches found for Username: '$CredentialAccount' Resource: '$CredentialResource'"Add-SbPAMActionLog -Type Error -Message "BYOV: $Message"return $null}return $result}### If this is an activity then use the LoginAccountName$CredentialAccount = $null$CredentialResource = $nullif ($null -ne $Options.ActivitySession) {$CredentialAccount = $Options.ActivitySession.LoginAccountName}$Message = "CredentialAccount: $CredentialAccount"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"### This is a service account, so the info should be in the Credential$IsServiceAccount = $falseif ($null -eq $CredentialAccount) {$CredentialAccount = $Credential.Username$IsServiceAccount = $true}$Message = "CredentialAccount: $CredentialAccount"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"if ($CredentialAccount -match ".*@.*") {$Parts = $CredentialAccount.Split("@")$CredentialAccount = $Parts[0]$CredentialResource = $Parts[1]}elseif ($CredentialAccount -match ".*\.*") {$Parts = $CredentialAccount.Split("")$CredentialAccount = $Parts[1]$CredentialResource = $Parts[0]}else {if ($IsServiceAccount) {$CredentialResource = $Credential.Domain}else {$CredentialResource = $Options.TargetHost.DnsHostName}}$result = Get-CredentialMatch -CredentialAccount $CredentialAccount -CredentialResource $CredentialResource -Token $Token -Uri $Uri -CredentialType 1if ($null -eq $result) {if ($InsecureAllowServiceAccounts){Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (UserAccount)"$result = Get-CredentialMatch -CredentialAccount $CredentialAccount -CredentialResource $CredentialResource -Token $Token -Uri $Uri -CredentialType 0if ($null -eq $result) {Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (ServiceAccount)"}}else{Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (UserAccount)"}}if ($null -eq $result) {Add-SbPAMActionLog -Type Error -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource failed"return $null}if ($null -ne $result) {$Params = @{RestApiToken = $Token;Uri = "$($Uri.TrimEnd("/"))/api/v1/Credential/$($result.CredentialId)?showPassword=true";}$result = Invoke-SbPAMRest @Params# To support domain users in secret vaultsif ($result.Username -contains "") {$Parts = $result.Username.split("")$Credential.Username = $Parts[1]$Credential.Domain = $Parts[0]}else {$Credential.Username = $result.Username$Credential.Domain = $result.Domain}$Credential.Password = $result.PasswordAdd-SbPAMActionLog -Type Info -Message "Returning Username: '$($Credential.Username)' CredentialResource: '$($Credential.Domain)'"return $Credential}else {$Message = "Unable to find credential for $CredentialAccount $CredentialResource"Add-SbPAMActionLog -Type Error -Message "BYOV: $Message"return $null} -
Edit line 12 of the Checkout Script Block so that the
InsecureAllowServiceAccountsvariable istrue:$InsecureAllowServiceAccounts = $true
Checkin Instructions (Optional - for Password Rotation)
-
Copy and paste the following script into the Checkin Script Block field:
param ($Options,$Credential)$Token = $Options.RestApiToken$Uri = $Options.RestApiUri###### Allow service accounts to be checked out## NOTE This is not recommended.## Service accounts should not be used for interactive logins####$InsecureAllowServiceAccounts = $falsefunction Get-CredentialMatch {[CmdletBinding()]param ($CredentialAccount,$CredentialResource,$Token,$Uri,$CredentialType = 1)$credentials = @()$skip = 0$take = 100$result = $nullif ($null -ne $CredentialAccount) {$FilterText = "$($CredentialAccount)"$Message = "FILTERTEXT: $FilterText"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"do {$Params = @{RestApiToken = $Token;Uri = "$($Uri.TrimEnd("/"))/api/v1/Credential/Search?skip=$skip&take=$take&filterText=$FilterText&credentialType=$CredentialType";}$result = Invoke-SbPAMRest @Params<#$Message = (ConvertTo-Json $result)Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"#>$result.Data | ForEach-Object { $credentials += $_ }$skip += $take} until ($credentials.Count -ge $result.RecordsTotal)$credentials | Foreach-Object {$Message = "FOUND: $($_.Id) UserName: '$($_.UserName)' Resource: '$($_.Domain)'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"}$Message = "Find UserName -eq '$CredentialAccount' -and Resource -eq '$CredentialResource'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"if ($null -ne $CredentialResource) {$result = $credentials | Where-Object { $_.Username -eq $CredentialAccount -and $_.Domain -eq $CredentialResource }}else {$result = $credentials | Where-Object { $_.Username -eq $CredentialAccount }}if ($null -eq $result) {# Try RESOURCE\USERNAME$Test = "$CredentialResource\$CredentialAccount"$Message = "Find UserName -eq '$Test'"$result = $credentials | Where-Object -Property UserName -eq $Test}if ($null -eq $result) {$Test = "$($Options.TargetHost.DnsHostName)\$CredentialAccount"if ($null -ne $Options.TargetHost.NetBiosName) {$Test = "$($Options.TargetHost.NetBiosName)\$CredentialAccount"}$Message = "Find UserName -eq $Test"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"$result = $credentials | Where-Object -Property UserName -eq $Test}else {$Message = "FOUND Username: '$($result.Username)' Resource: '$($result.Domain)'"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"}}if ($result.Count -gt 1) {$Message = "Multiple matches found for Username: '$CredentialAccount' Resource: '$CredentialResource'"Add-SbPAMActionLog -Type Error -Message "BYOV: $Message"return $null}return $result}### If this is an activity then use the LoginAccountName$CredentialAccount = $null$CredentialResource = $nullif ($null -ne $Options.ActivitySession) {$CredentialAccount = $Options.ActivitySession.LoginAccountName}$Message = "CredentialAccount: $CredentialAccount"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"### This is a service account, so the info should be in the Credential$IsServiceAccount = $falseif ($null -eq $CredentialAccount) {$CredentialAccount = $Credential.Username$IsServiceAccount = $true}$Message = "CredentialAccount: $CredentialAccount"Add-SbPAMActionLog -Type Info -Message "BYOV: $Message"if ($CredentialAccount -match ".*@.*") {$Parts = $CredentialAccount.Split("@")$CredentialAccount = $Parts[0]$CredentialResource = $Parts[1]}elseif ($CredentialAccount -match ".*\.*") {$Parts = $CredentialAccount.Split("")$CredentialAccount = $Parts[1]$CredentialResource = $Parts[0]}else {if ($IsServiceAccount) {$CredentialResource = $Credential.Domain}else {$CredentialResource = $Options.TargetHost.DnsHostName}}$result = Get-CredentialMatch -CredentialAccount $CredentialAccount -CredentialResource $CredentialResource -Token $Token -Uri $Uri -CredentialType 1if ($null -eq $result) {if ($InsecureAllowServiceAccounts){Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (UserAccount)"$result = Get-CredentialMatch -CredentialAccount $CredentialAccount -CredentialResource $CredentialResource -Token $Token -Uri $Uri -CredentialType 0if ($null -eq $result) {Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (ServiceAccount)"}}else{Add-SbPAMActionLog -Type Info -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource returned null (UserAccount)"}}if ($null -eq $result) {Add-SbPAMActionLog -Type Error -Message "Search using CredentialAccount: $CredentialAccount and CredentialResource: $CredentialResource failed"return $null}if ($null -ne $result) {$Params = @{RestApiToken = $Token;Uri = "$($Uri.TrimEnd("/"))/api/v1/Credential/$($result.CredentialId)?showPassword=false";}$Body = @{Ids = @()}$Body.Ids += $result.Id;## Rotating passwordAdd-SbPAMActionLog -Type Info -Message "Rotating Username: '$($Credential.Username)' CredentialResource: '$($Credential.Domain)'"Invoke-SbPAMRest -Uri "$($Uri.TrimEnd("/"))/api/v1/ManagedUser/RotateAccounts" -Method Post -Body (ConvertTo-Json $Body) -RestApiToken $Token -ErrorAction Stopreturn $Credential}else {$Message = "Unable to find credential for $CredentialAccount $CredentialResource"Add-SbPAMActionLog -Type Error -Message "BYOV: $Message"} -
Edit line 12 of the Checkin Script Block so that the
InsecureAllowServiceAccountsvariable istrue:$InsecureAllowServiceAccounts = $true
Configuring an Activity
-
In the Privilege Secure console, go to the Activities menu.
-
Click the green plus icon to create a new activity.
-
Configure it with the following values:
Field Value Name <anything>Description <anything>Platform None specifiedLogin Account VaultActivity Type InteractiveLogin Account Template <your account>Vault Connector <the BYOV vault connector configured earlier> -
After the activity is properly configured, click Save.
You can now assign this activity to an access policy, and access it by selecting its activity card on the My Activities page.