Using Thycotic Secret Server as an External Credential Store - Part 1(Mid Server)

Update: I decided to not use refresh_tokens due to configuration on Secret Server not making it viable. I also made some changes to the CredentialResolver.jar and the whole flow of how it works and where the config files live. Updates to follow soon

Part 1 - Configuring the Mid Server

As the first step of setting up Secret Server to work with ITOM, I will be configuring the Mid Server. I will be using Grant File Mode and a refresh token for managing the access token. There are other options, see the references below for more information.

1. Update the config.xml

First we need to update the config.xml file in your agent folder. Modify and add the following to the config.xml file.

   <parameter name="ext.tss.url" value="https://mySecretServer.mydomain.corp/SecretServer" />
   <parameter name="ext.tss.oauth2.grant_file" value="oauth2_grant.json" />
   <parameter name="ext.tss.allow.self_signed_certificates" value="false" />

2. Setup token refresh

***Important *** You will need to Enable Refresh Tokens for Web Services in Secret Server, if not already enabled.

  1. Create a folder to contain all of your scripts/files (c:\thycotic)

  2. Modify and create a JSON configuration file. See the below example

{
    "url": "https://mySecretServer.mydomain.corp/SecretServer/",
    "password_file": "c:\\thycotic\\oauth_token.xml",
    "log_file": "c:\\thycotic\\refreshLog.log",
    "output_files": [
         "c:\\servicenow\\ServiceNow MID Server 1\\agent\\oauth2_grant.json",
         "c:\\servicenow\\ServiceNow MID Server 2\\agent\\oauth2_grant.json"

    ]


}
  1. Create the following powershell scripts
    1. getInitialToken.ps1 - This will request a refresh token using Username/Password. The refresh token will be stored in plain text initially, but will be secure string after the first run of the refresh script.
  param(
    [string]$configFile = "config_refresh.json"
  
)

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
  $config = gc $configFile | ConvertFrom-Json;
    $SecretServerURL = $config.url;
    $PasswordFile = $config.password_file;

$cred = Get-Credential  -Message "Enter username/password to access SecretServer API"
$curLocation = $PWD.path;

$body = @{
    "grant_type" = "password"
    "username" = $cred.username
    "password" = $cred.GetNetworkCredential().password
}

$response = Invoke-RestMethod -Method POST -Uri "$SecretServerUrl/oauth2/token" -Body $body -ContentType 'application/x-www-form-urlencoded'
$value = $response.access_token
$response.refresh_token|Export-Clixml -Path $passwordFile;


write-host( "Token written to " + $filePath + "(Expires In " + ($response.expires_in / 60) + " minutes)");


  1. refresh_oath_token.ps1 - It is important that this is run as the User the scheduled task will run as(or wait until scheduled task is created). The encrypted string is only readable by the user that created, on the machine it was created on.
param(

 [string]$configFile = "config_refresh.json"
 
 
)


function logOutput($err) {
 #future state: Use custom event log instead?
  "$(get-date) :$($err)"|out-file -Append -FilePath $global:logFile
}


function getToken($configFile) {

 try {
 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

 #load our variable from config file.
 $config = gc $configFile | ConvertFrom-Json;
 $SecretServerURL = $config.url;
 $PasswordFile = $config.password_file;
 [array]$output_files = $config.output_files;
 $global:logFile = $config.log_file;

 if ($global:logFile -eq $null) {
     $global:logFile = "$($PWD.path)\tokenRefresh.log"
 }
     
      
 
 <# Get our refresh token to use in request
  Initial run refresh token will be plain text.  Will be encrypted with new token.  This is used for the initial run or their is an issue where we need to rest the refresh token. 
  Encrypted token only readable by the account that created and on the machine that created
  #>
 $token = Import-Clixml -Path $PasswordFile

 if ($token.getType().name -eq 'SecureString') {
     $token = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($token))
 }

 #Set x-www-form value pairs
 $body = @{
     "grant_type"    = "refresh_token"
     "refresh_token" = $token
 }

#get new token.  Make sure to set contentype 'application/x-www-form-urlencoded'
     $response = Invoke-RestMethod -Method POST -Uri "$SecretServerUrl/oauth2/token" -Body $body -ContentType 'application/x-www-form-urlencoded'

 
 $access_token = $response.access_token;
 $refresh_token = $response.refresh_token;
     
 #Write new access token to mid servers auth file refenced in config.xml
 foreach ($file in $output_files) {
     Set-Content -Path $file -Encoding Ascii -Force -Value $access_token -NoNewline
 }

 #save new refresh token
 $refresh_token | ConvertTo-SecureString -AsPlainText -Force | Export-Clixml -Path $PasswordFile
 logOutput "Token refreshed"
} catch {
 logOutput  $_.Exception.Message
 return 1;
}
 return 0;
}



exit($(getToken $configFile));

  1. Create Scheduled task to run refresh script. Verify the expiration time of the access token. By default it is 20 minutes. I setup my scheduled task to run every 18 minutes.

3. References

Related Posts