Venafi TPP - Generate OAuth Token

Octopus.Script exported 2021-07-30 by harrisonmeister belongs to ‘Venafi’ category.

This step template will authenticate against a Venafi TPP instance and generate an OAuth token for specified scope/privileges using the VenafiPS PowerShell module’s New-TppToken (an alias of the VdcToken function).

The following properties from the resulting OAuth token will be created as Octopus sensitive variables:

  • access_token created with the name AccessToken
  • Expires created with the name AccessTokenExpires in the format yyyy-MM-ddTHH:mm:ss
  • refresh_token created with the name RefreshToken
  • refresh_until created with the name RefreshTokenExpires in the format yyyy-MM-ddTHH:mm:ss. Note: This value can be empty.

These output variables can be used in additional deployment or runbook steps.


Required:

  • The VenafiPS PowerShell module installed on the deployment target or worker. If the module can’t be found, the step will attempt to download a version from the PowerShell gallery.

Notes:

  • Tested on Octopus 2021.2.
  • Tested with VenafiPS 3.1.5.
  • Tested with both Windows PowerShell and PowerShell Core on Linux.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Venafi TPP Server

Venafi.TPP.OAuthToken.Server =

The URL of the Venafi TPP instance you are connecting to.

For example: https://mytppserver.example.com

Venafi Application ClientID

Venafi.TPP.OAuthToken.ClientID =

Application Id (also known as ClientId) configured in Venafi for token-based authentication.

Venafi Username

Venafi.TPP.OAuthToken.Username =

Username to request API token.

Venafi Password

Venafi.TPP.OAuthToken.Password =

Password to request API token.

Access token scope

Venafi.TPP.OAuthToken.Scope =

Scopes and privilege restrictions for the access token. Scopes can include:

  • agent
  • certificate
  • code signing
  • configuration
  • restricted
  • security
  • ssh
  • statistics

See the Venafi Auth SDK for more info.

Multiple values can be supplied separated by ;.

For a privilege restriction of none or read, just use the scope as the value. For example, to include management of certificates and include ssh with no privilege restriction, use: certificate:manage;ssh.

If multiple values for the same scope are provided they will be concatenated, unless a value of no privilege is found. If that occurs, then the “last entry” wins.

Script body

Steps based on this template will execute the following PowerShell script.

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ErrorActionPreference = 'Stop'

# Variables
$StepName = $OctopusParameters["Octopus.Step.Name"]
$Server = $OctopusParameters["Venafi.TPP.OAuthToken.Server"]
$ClientID = $OctopusParameters["Venafi.TPP.OAuthToken.ClientID"]
$Username = $OctopusParameters["Venafi.TPP.OAuthToken.Username"]
$Password = $OctopusParameters["Venafi.TPP.OAuthToken.Password"]
$Scopes = $OctopusParameters["Venafi.TPP.OAuthToken.Scope"]

# Validation
if ([string]::IsNullOrWhiteSpace($Server)) {
    throw "Required parameter Venafi.TPP.OAuthToken.Server not specified"
}
if ([string]::IsNullOrWhiteSpace($ClientID)) {
    throw "Required parameter Venafi.TPP.OAuthToken.ClientID not specified"
}
if ([string]::IsNullOrWhiteSpace($Username)) {
    throw "Required parameter Venafi.TPP.OAuthToken.Username not specified"
}
if ([string]::IsNullOrWhiteSpace($Password)) {
    throw "Required parameter Venafi.TPP.OAuthToken.Password not specified"
}
if ([string]::IsNullOrWhiteSpace($Scopes)) {
    throw "Required parameter Venafi.TPP.OAuthToken.Scope not specified"
}

# Clean-up
$Server = $Server.TrimEnd('/')

# Required Modules
function Get-NugetPackageProviderNotInstalled {
    # See if the nuget package provider has been installed
    return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))
}

# Check to see if the package provider has been installed
if ((Get-NugetPackageProviderNotInstalled) -ne $false) {
    Write-Host "Nuget package provider not found, installing ..."    
    Install-PackageProvider -Name Nuget -Force -Scope CurrentUser
}

Write-Host "Checking for required VenafiPS module ..."
$required_venafips_version = 3.1.5
$module_available = Get-Module -ListAvailable -Name VenafiPS | Where-Object { $_.Version -ge $required_venafips_version }
if (-not ($module_available)) {
    Write-Host "Installing VenafiPS module ..."
    Install-Module -Name VenafiPS -MinimumVersion 3.1.5 -Scope CurrentUser -Force
}
else {
    $first_match = $module_available | Select-Object -First 1 
    Write-Host "Found version: $($first_match.Version)"
}

Write-Host "Importing VenafiPS module ..."
Import-Module VenafiPS

$AccessTokenScope = @{}

$Scopes -Split ";" | ForEach-Object {
    $Scope = ($_ -Split ":")
    $Type = $Scope[0]
    $Privileges = $null
    
    if ($Scope.Length -gt 1) {
        $Privileges = $Scope[1].TrimEnd(",")
    }
    
    if ($AccessTokenScope.ContainsKey($Type)) {
        $CurrentPrivileges = $AccessTokenScope[$Type]
        # If no privilege, set to $null
        if ([string]::IsNullOrWhiteSpace($Privileges)) {
            $AccessTokenScope[$Type] = $null
        }
        else {
            $AccessTokenScope[$Type] = if ([string]::IsNullOrWhiteSpace($CurrentPrivileges)) { $Privileges } else { "$($CurrentPrivileges),$Privileges" }  
        }
    }
    else {
        $AccessTokenScope.Add($Type, $Privileges)
    }
}

if ($AccessTokenScope.Keys.Count -lt 1) {
    throw "No scopes could be determined!"
}

$scopeString = @($AccessTokenScope.GetEnumerator() | ForEach-Object { if ($_.Value) { '{0}:{1}' -f $_.Key, $_.Value } else { $_.Key } }) -join ';'

# Get TPP access token
[PSCredential]$Credential = New-Object System.Management.Automation.PSCredential ($Username, (ConvertTo-SecureString $Password -AsPlainText -Force))

Write-Host "Requesting new OAuth token from: $Server for ClientId: $ClientID with scope '$scopeString' ..."
$tppTokenResponse = New-TppToken -AuthServer $Server -ClientId $ClientID -Scope $AccessTokenScope -Credential $Credential

$AccessToken = $tppTokenResponse.AccessToken.GetNetworkCredential().Password
$Expiry = $tppTokenResponse.Expires.ToString("s")
$RefreshToken = $tppTokenResponse.RefreshToken.GetNetworkCredential().Password
$RefreshExpires = $tppTokenResponse.RefreshExpires

# Refresh Expiry can be $null
if ($null -ne $RefreshExpires) {
    $RefreshExpires = $RefreshExpires.ToString("s")
}

Set-OctopusVariable -Name "AccessToken" -Value $AccessToken -Sensitive
Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.AccessToken}"
Set-OctopusVariable -Name "AccessTokenExpires" -Value $Expiry -Sensitive
Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.AccessTokenExpires}"
Set-OctopusVariable -Name "RefreshToken" -Value $RefreshToken -Sensitive
Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.RefreshToken}"
Set-OctopusVariable -Name "RefreshTokenExpires" -Value $RefreshExpires -Sensitive
Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.RefreshTokenExpires}"

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "7e6f7f03-260a-4b52-9377-66f1c69b77d8",
  "Name": "Venafi TPP - Generate OAuth Token",
  "Description": "This step template will authenticate against a Venafi TPP instance and generate an OAuth token for specified scope/privileges using the VenafiPS PowerShell module's `New-TppToken` (an alias of the [VdcToken](https://venafips.readthedocs.io/en/latest/functions/New-VdcToken/) function).\n\nThe following properties from the resulting OAuth token will be created as [Octopus sensitive variables](https://octopus.com/docs/projects/variables/output-variables#sensitive-output-variables):\n\n- `access_token` created with the name `AccessToken`\n- `Expires` created with the name `AccessTokenExpires` in the format `yyyy-MM-ddTHH:mm:ss`\n- `refresh_token` created with the name `RefreshToken`\n- `refresh_until` created with the name `RefreshTokenExpires` in the format `yyyy-MM-ddTHH:mm:ss`. *Note: This value can be empty*.\n\nThese output variables can be used in additional deployment or runbook steps.\n\n---\n\n**Required:** \n- The `VenafiPS` PowerShell module installed on the deployment target or worker. If the module can't be found, the step will attempt to download a version from the [PowerShell gallery](https://www.powershellgallery.com/packages/VenafiPS).\n\nNotes:\n\n- Tested on Octopus `2021.2`.\n- Tested with VenafiPS `3.1.5`.\n- Tested with both Windows PowerShell and PowerShell Core on Linux.",
  "Version": 3,
  "ExportedAt": "2021-07-30T10:36:31.301Z",
  "ActionType": "Octopus.Script",
  "Author": "harrisonmeister",
  "Packages": [],
  "Parameters": [
    {
      "Id": "7ca2062d-9153-4606-bbab-441c893f9739",
      "Name": "Venafi.TPP.OAuthToken.Server",
      "Label": "Venafi TPP Server",
      "HelpText": "The URL of the Venafi TPP instance you are connecting to.\n\nFor example: `https://mytppserver.example.com`",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "57631dfd-965b-4bfa-9f34-5e9147cdb702",
      "Name": "Venafi.TPP.OAuthToken.ClientID",
      "Label": "Venafi Application ClientID",
      "HelpText": "Application Id (also known as `ClientId`) configured in Venafi for token-based authentication.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "83bfad97-50d1-49b9-9d9b-dc2ba87d9281",
      "Name": "Venafi.TPP.OAuthToken.Username",
      "Label": "Venafi Username",
      "HelpText": "Username to request API token.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "05280b11-3dd6-41d7-a970-2328478a4b52",
      "Name": "Venafi.TPP.OAuthToken.Password",
      "Label": "Venafi Password",
      "HelpText": "Password to request API token.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "b7edd6a4-20bb-47fe-8181-42ca5af9adb2",
      "Name": "Venafi.TPP.OAuthToken.Scope",
      "Label": "Access token scope",
      "HelpText": "Scopes and privilege restrictions for the access token. Scopes can include:\n\n- `agent`\n- `certificate`\n- `code signing`\n- `configuration`\n- `restricted`\n- `security`\n- `ssh`\n- `statistics`\n\nSee the [Venafi Auth SDK](https://docs.venafi.com/Docs/21.1/TopNav/Content/SDK/AuthSDK/t-SDKa-Setup-OAuth.php) for more info.\n\nMultiple values can be supplied separated by `;`. \n\nFor a privilege restriction of none or read, just use the scope as the value. For example, to include management of certificates and include ssh with no privilege restriction, use: `certificate:manage;ssh`.\n\nIf multiple values for the same scope are provided they will be concatenated, *unless* a value of no privilege is found. If that occurs, then the \"last entry\" wins.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$ErrorActionPreference = 'Stop'\n\n# Variables\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n$Server = $OctopusParameters[\"Venafi.TPP.OAuthToken.Server\"]\n$ClientID = $OctopusParameters[\"Venafi.TPP.OAuthToken.ClientID\"]\n$Username = $OctopusParameters[\"Venafi.TPP.OAuthToken.Username\"]\n$Password = $OctopusParameters[\"Venafi.TPP.OAuthToken.Password\"]\n$Scopes = $OctopusParameters[\"Venafi.TPP.OAuthToken.Scope\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($Server)) {\n    throw \"Required parameter Venafi.TPP.OAuthToken.Server not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ClientID)) {\n    throw \"Required parameter Venafi.TPP.OAuthToken.ClientID not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($Username)) {\n    throw \"Required parameter Venafi.TPP.OAuthToken.Username not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($Password)) {\n    throw \"Required parameter Venafi.TPP.OAuthToken.Password not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($Scopes)) {\n    throw \"Required parameter Venafi.TPP.OAuthToken.Scope not specified\"\n}\n\n# Clean-up\n$Server = $Server.TrimEnd('/')\n\n# Required Modules\nfunction Get-NugetPackageProviderNotInstalled {\n    # See if the nuget package provider has been installed\n    return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\n# Check to see if the package provider has been installed\nif ((Get-NugetPackageProviderNotInstalled) -ne $false) {\n    Write-Host \"Nuget package provider not found, installing ...\"    \n    Install-PackageProvider -Name Nuget -Force -Scope CurrentUser\n}\n\nWrite-Host \"Checking for required VenafiPS module ...\"\n$required_venafips_version = 3.1.5\n$module_available = Get-Module -ListAvailable -Name VenafiPS | Where-Object { $_.Version -ge $required_venafips_version }\nif (-not ($module_available)) {\n    Write-Host \"Installing VenafiPS module ...\"\n    Install-Module -Name VenafiPS -MinimumVersion 3.1.5 -Scope CurrentUser -Force\n}\nelse {\n    $first_match = $module_available | Select-Object -First 1 \n    Write-Host \"Found version: $($first_match.Version)\"\n}\n\nWrite-Host \"Importing VenafiPS module ...\"\nImport-Module VenafiPS\n\n$AccessTokenScope = @{}\n\n$Scopes -Split \";\" | ForEach-Object {\n    $Scope = ($_ -Split \":\")\n    $Type = $Scope[0]\n    $Privileges = $null\n    \n    if ($Scope.Length -gt 1) {\n        $Privileges = $Scope[1].TrimEnd(\",\")\n    }\n    \n    if ($AccessTokenScope.ContainsKey($Type)) {\n        $CurrentPrivileges = $AccessTokenScope[$Type]\n        # If no privilege, set to $null\n        if ([string]::IsNullOrWhiteSpace($Privileges)) {\n            $AccessTokenScope[$Type] = $null\n        }\n        else {\n            $AccessTokenScope[$Type] = if ([string]::IsNullOrWhiteSpace($CurrentPrivileges)) { $Privileges } else { \"$($CurrentPrivileges),$Privileges\" }  \n        }\n    }\n    else {\n        $AccessTokenScope.Add($Type, $Privileges)\n    }\n}\n\nif ($AccessTokenScope.Keys.Count -lt 1) {\n    throw \"No scopes could be determined!\"\n}\n\n$scopeString = @($AccessTokenScope.GetEnumerator() | ForEach-Object { if ($_.Value) { '{0}:{1}' -f $_.Key, $_.Value } else { $_.Key } }) -join ';'\n\n# Get TPP access token\n[PSCredential]$Credential = New-Object System.Management.Automation.PSCredential ($Username, (ConvertTo-SecureString $Password -AsPlainText -Force))\n\nWrite-Host \"Requesting new OAuth token from: $Server for ClientId: $ClientID with scope '$scopeString' ...\"\n$tppTokenResponse = New-TppToken -AuthServer $Server -ClientId $ClientID -Scope $AccessTokenScope -Credential $Credential\n\n$AccessToken = $tppTokenResponse.AccessToken.GetNetworkCredential().Password\n$Expiry = $tppTokenResponse.Expires.ToString(\"s\")\n$RefreshToken = $tppTokenResponse.RefreshToken.GetNetworkCredential().Password\n$RefreshExpires = $tppTokenResponse.RefreshExpires\n\n# Refresh Expiry can be $null\nif ($null -ne $RefreshExpires) {\n    $RefreshExpires = $RefreshExpires.ToString(\"s\")\n}\n\nSet-OctopusVariable -Name \"AccessToken\" -Value $AccessToken -Sensitive\nWrite-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.AccessToken}\"\nSet-OctopusVariable -Name \"AccessTokenExpires\" -Value $Expiry -Sensitive\nWrite-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.AccessTokenExpires}\"\nSet-OctopusVariable -Name \"RefreshToken\" -Value $RefreshToken -Sensitive\nWrite-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.RefreshToken}\"\nSet-OctopusVariable -Name \"RefreshTokenExpires\" -Value $RefreshExpires -Sensitive\nWrite-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.RefreshTokenExpires}\""
  },
  "Category": "Venafi",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/venafi-tpp-generate-oauth-token.json",
  "Website": "/step-templates/7e6f7f03-260a-4b52-9377-66f1c69b77d8",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Friday, July 30, 2021