HashiCorp Vault - AppRole Get Wrapped Secret ID

Octopus.Script exported 2022-09-18 by harrisonmeister belongs to ‘HashiCorp Vault’ category.

This step generates a response-wrapped Secret ID for an AppRole from a HashiCorp Vault server.


Two properties from the response will be made available as sensitive Output variables:

  • wrap_info.token named WrappedToken - This is the wrapped token used to retrieve the actual Secret ID from Vault.
  • wrap_info.creation_path named WrappedTokenCreationPath - This is the creation path of the token to allow you to validate no malfeasance has occurred.

This step template makes use of the Rest API, so no other dependencies are needed.


Required:

  • The Vault server must be unsealed.
  • The full path where the AppRole auth method is mounted.
  • A RoleName.
  • A TTL for the wrapped token (Default: 120s).
  • The Auth token used to authenticate with Vault. This token should be of limited scope and should only retrieve wrapped SecretIDs. See the HashiCorp documentation for further information.

Optional

  • A Vault namespace to use. Nested namespaces can also be supplied, e.g. ns1/ns2. Note: This field is only supported on Vault Enterprise .

Notes:

  • Tested on Vault Server 1.11.3.
  • Tested on both PowerShell Desktop and PowerShell Core.

Parameters

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

Vault Server URL

Vault.AppRole.WrappedSecretID.VaultAddress =

The URL of the Vault instance you are connecting to. Port should be included (The default is 8200). For example:

https://myvault.local:8200/

API version

Vault.AppRole.WrappedSecretID.ApiVersion = v1

All API routes are prefixed with a version e.g. /v1/.

See the API documentation for further details.

Namespace (Optional)

Vault.AppRole.WrappedSecretID.Namespace =

The optional namespace to use. Nested namespaces can also be supplied, e.g. ns1/ns2.

Note: This field is only supported on Vault Enterprise .

App Role Path

Vault.AppRole.WrappedSecretID.AppRolePath = /auth/approle

The path where the approle auth method was mounted. The default path is /auth/approle. If the AppRole auth method was mounted at a different path, for example my-path, then specify /my-path instead.

Role Name

Vault.AppRole.WrappedSecretID.RoleName =

The role name of the AppRole.

Time-to-live (TTL)

Vault.AppRole.WrappedSecretID.TTL = 120s

The TTL of the response-wrapping token itself. Enter a value in seconds. The default is: 120s

Auth token

Vault.AppRole.WrappedSecretID.AuthToken =

The Auth token used to authenticate with Vault to generate a response-wrapped Secret ID.

Script body

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

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

# Variables
$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS = $OctopusParameters["Vault.AppRole.WrappedSecretID.VaultAddress"]
$VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION = $OctopusParameters["Vault.AppRole.WrappedSecretID.ApiVersion"]
$VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE = $OctopusParameters["Vault.AppRole.WrappedSecretID.Namespace"]
$VAULT_APPROLE_WRAPPED_SECRETID_PATH = $OctopusParameters["Vault.AppRole.WrappedSecretID.AppRolePath"]
$VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME = $OctopusParameters["Vault.AppRole.WrappedSecretID.RoleName"]
$VAULT_APPROLE_WRAPPED_SECRETID_TTL = $OctopusParameters["Vault.AppRole.WrappedSecretID.TTL"]
$VAULT_APPROLE_WRAPPED_SECRETID_TOKEN = $OctopusParameters["Vault.AppRole.WrappedSecretID.AuthToken"]

# Validation
if ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS)) {
   throw "Required parameter VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS not specified"
}
if ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION)) {
	throw "Required parameter VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION not specified"
}
if ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_PATH)) {
	throw "Required parameter VAULT_APPROLE_WRAPPED_SECRETID_AUTH_PATH not specified"
}
if ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME)) {
	throw "Required parameter VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME not specified"
}
if ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_TOKEN)) {
	throw "Required parameter VAULT_APPROLE_WRAPPED_SECRETID_TOKEN not specified"
}

# Helper functions
###############################################################################
function Get-WebRequestErrorBody {
    param (
        $RequestError
    )

    # Powershell < 6 you can read the Exception
    if ($PSVersionTable.PSVersion.Major -lt 6) {
        if ($RequestError.Exception.Response) {
            $reader = New-Object System.IO.StreamReader($RequestError.Exception.Response.GetResponseStream())
            $reader.BaseStream.Position = 0
            $reader.DiscardBufferedData()
            $rawResponse = $reader.ReadToEnd()
            $response = ""
            try {$response = $rawResponse | ConvertFrom-Json} catch {$response=$rawResponse}
            return $response
        }
    }
    else {
        return $RequestError.ErrorDetails.Message
    }
}
###############################################################################

$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS = $VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS.TrimEnd('/')
$VAULT_APPROLE_WRAPPED_SECRETID_PATH = $VAULT_APPROLE_WRAPPED_SECRETID_PATH.TrimStart('/').TrimEnd('/')
$VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME = $VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME.TrimStart('/').TrimEnd('/')

# Local variables
$StepName = $OctopusParameters["Octopus.Step.Name"]

try
{
	$headers = @{
        "X-Vault-Token" = $VAULT_APPROLE_WRAPPED_SECRETID_TOKEN
        "X-Vault-Wrap-Ttl" = $VAULT_APPROLE_WRAPPED_SECRETID_TTL
    }
    if (-not [string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE)) {
        Write-Verbose "Setting 'X-Vault-Namespace' header to: $VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE"
        $Headers.Add("X-Vault-Namespace", $VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE)
    }
    
    $uri = "$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS/$VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION/$VAULT_APPROLE_WRAPPED_SECRETID_PATH/role/$([uri]::EscapeDataString($VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME))/secret-id"
    Write-Verbose "Making Put request to $uri"
    $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Put
    
    if($null -ne $response) {
    	Set-OctopusVariable -Name "WrappedToken" -Value $response.wrap_info.token -Sensitive
        Set-OctopusVariable -Name "WrappedTokenCreationPath" -Value $response.wrap_info.creation_path -Sensitive
        Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.WrappedToken}"
        Write-Host "Created output variable: ##{Octopus.Action[$StepName].Output.WrappedTokenCreationPath}"
    }
    else {
    	Write-Error "Null or Empty response returned from Vault server" -Category InvalidResult
    }
}
catch {
    $ExceptionMessage = $_.Exception.Message
    $ErrorBody = Get-WebRequestErrorBody -RequestError $_
    $Message = "An error occurred getting a wrapped secretid: $ExceptionMessage"
    $AdditionalDetail = ""
    if (![string]::IsNullOrWhiteSpace($ErrorBody)) {
        if ($null -ne $ErrorBody.errors) {
            $AdditionalDetail = $ErrorBody.errors -Join ","   
        }
        else {
            $errorDetails = $null
            try { $errorDetails = ConvertFrom-Json $ErrorBody } catch {}
            $AdditionalDetail += if ($null -ne $errorDetails) { $errorDetails.errors -Join "," } else { $ErrorBody } 
        }
    }
    
    if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {
        $Message += "`n`tDetail: $AdditionalDetail"
    }

    Write-Error $Message -Category ConnectionError
}

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": "76827264-af27-46d0-913a-e093a4f0db48",
  "Name": "HashiCorp Vault - AppRole Get Wrapped Secret ID",
  "Description": "This step generates a response-wrapped Secret ID for an [AppRole](https://www.vaultproject.io/docs/auth/approle) from a HashiCorp Vault server.\n\n---\n\nTwo properties from the response will be made available as [sensitive Output variables](https://octopus.com/docs/projects/variables/output-variables#sensitive-output-variables):\n\n- `wrap_info.token` named `WrappedToken` - This is the wrapped token used to retrieve the actual Secret ID from Vault.\n- `wrap_info.creation_path` named `WrappedTokenCreationPath` - This is the creation path of the token to allow you to [validate no malfeasance](https://www.vaultproject.io/docs/concepts/response-wrapping#response-wrapping-token-validation) has occurred.\n\nThis step template makes use of the [Rest API](https://www.vaultproject.io/api-docs/auth/approle#login-with-approle), so no other dependencies are needed. \n\n---\n\n**Required:** \n- The Vault server must be [unsealed](https://www.vaultproject.io/docs/concepts/seal).\n- The full path where the AppRole auth method is mounted.\n- A `RoleName`.\n- A TTL for the wrapped token (Default: `120s`).\n- The [Auth token](https://www.vaultproject.io/docs/auth/token) used to authenticate with Vault. This token should be of limited scope and should only retrieve wrapped SecretIDs. See the [HashiCorp documentation](https://learn.hashicorp.com/tutorials/vault/pattern-approle?in=vault/recommended-patterns#vault-returns-a-token) for further information.\n\n---\n\n*Optional*\n- A Vault [namespace](https://www.vaultproject.io/docs/enterprise/namespaces) to use. Nested namespaces can also be supplied, e.g. `ns1/ns2`. **Note:** This field is only supported on [Vault Enterprise](https://www.hashicorp.com/products/vault) .\n\n---\n\nNotes:\n\n- Tested on Vault Server `1.11.3`.\n- Tested on both PowerShell Desktop and PowerShell Core.",
  "Version": 5,
  "ExportedAt": "2022-09-18T08:56:29.022Z",
  "ActionType": "Octopus.Script",
  "Author": "harrisonmeister",
  "Packages": [],
  "Parameters": [
    {
      "Id": "bbf1cf96-066a-43e8-8387-24131fa63feb",
      "Name": "Vault.AppRole.WrappedSecretID.VaultAddress",
      "Label": "Vault Server URL",
      "HelpText": "The URL of the Vault instance you are connecting to. Port should be included (The default is `8200`). For example:\n\n\n`https://myvault.local:8200/`",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "bd6ca2f2-2102-40e0-a1e0-36e526393203",
      "Name": "Vault.AppRole.WrappedSecretID.ApiVersion",
      "Label": "API version",
      "HelpText": "All API routes are prefixed with a version e.g. `/v1/`.\n\nSee the [API documentation](https://www.vaultproject.io/api-docs) for further details.",
      "DefaultValue": "v1",
      "DisplaySettings": {
        "Octopus.ControlType": "Select",
        "Octopus.SelectOptions": "v1|v1"
      }
    },
    {
      "Id": "30366827-71f8-42cc-ac0a-d05300ae6c8d",
      "Name": "Vault.AppRole.WrappedSecretID.Namespace",
      "Label": "Namespace (Optional)",
      "HelpText": "The _optional_ [namespace](https://www.vaultproject.io/docs/enterprise/namespaces) to use. Nested namespaces can also be supplied, e.g. `ns1/ns2`.\n\n**Note:** This field is only supported on [Vault Enterprise](https://www.hashicorp.com/products/vault) .",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "67c5d1c7-6373-4342-b02b-a7a6fa69402b",
      "Name": "Vault.AppRole.WrappedSecretID.AppRolePath",
      "Label": "App Role Path",
      "HelpText": "The path where the approle auth method was mounted. The default path is `/auth/approle`. If the AppRole auth method was mounted at a different path, for example `my-path`, then specify `/my-path` instead.",
      "DefaultValue": "/auth/approle",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "4c8ab1b0-36e3-4d19-9a45-557300bb0f06",
      "Name": "Vault.AppRole.WrappedSecretID.RoleName",
      "Label": "Role Name",
      "HelpText": "The role name of the [AppRole](https://www.vaultproject.io/api/auth/approle).",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "cc4afac6-6dc4-4c9f-bcb8-0ab9c2049523",
      "Name": "Vault.AppRole.WrappedSecretID.TTL",
      "Label": "Time-to-live (TTL)",
      "HelpText": "The TTL of the [response-wrapping token](https://www.vaultproject.io/docs/concepts/response-wrapping#response-wrapping-tokens) itself. Enter a value in seconds. The default is: `120s`",
      "DefaultValue": "120s",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "297871f1-a145-4dde-97ba-d7a9a0690cc6",
      "Name": "Vault.AppRole.WrappedSecretID.AuthToken",
      "Label": "Auth token",
      "HelpText": "The [Auth token](https://www.vaultproject.io/docs/auth/token) used to authenticate with Vault to generate a [response-wrapped](https://www.vaultproject.io/docs/concepts/response-wrapping) Secret ID.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\n# Variables\n$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.VaultAddress\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.ApiVersion\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.Namespace\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_PATH = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.AppRolePath\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.RoleName\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_TTL = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.TTL\"]\n$VAULT_APPROLE_WRAPPED_SECRETID_TOKEN = $OctopusParameters[\"Vault.AppRole.WrappedSecretID.AuthToken\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS)) {\n   throw \"Required parameter VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION)) {\n\tthrow \"Required parameter VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_PATH)) {\n\tthrow \"Required parameter VAULT_APPROLE_WRAPPED_SECRETID_AUTH_PATH not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME)) {\n\tthrow \"Required parameter VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_TOKEN)) {\n\tthrow \"Required parameter VAULT_APPROLE_WRAPPED_SECRETID_TOKEN not specified\"\n}\n\n# Helper functions\n###############################################################################\nfunction Get-WebRequestErrorBody {\n    param (\n        $RequestError\n    )\n\n    # Powershell < 6 you can read the Exception\n    if ($PSVersionTable.PSVersion.Major -lt 6) {\n        if ($RequestError.Exception.Response) {\n            $reader = New-Object System.IO.StreamReader($RequestError.Exception.Response.GetResponseStream())\n            $reader.BaseStream.Position = 0\n            $reader.DiscardBufferedData()\n            $rawResponse = $reader.ReadToEnd()\n            $response = \"\"\n            try {$response = $rawResponse | ConvertFrom-Json} catch {$response=$rawResponse}\n            return $response\n        }\n    }\n    else {\n        return $RequestError.ErrorDetails.Message\n    }\n}\n###############################################################################\n\n$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS = $VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS.TrimEnd('/')\n$VAULT_APPROLE_WRAPPED_SECRETID_PATH = $VAULT_APPROLE_WRAPPED_SECRETID_PATH.TrimStart('/').TrimEnd('/')\n$VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME = $VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME.TrimStart('/').TrimEnd('/')\n\n# Local variables\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n\ntry\n{\n\t$headers = @{\n        \"X-Vault-Token\" = $VAULT_APPROLE_WRAPPED_SECRETID_TOKEN\n        \"X-Vault-Wrap-Ttl\" = $VAULT_APPROLE_WRAPPED_SECRETID_TTL\n    }\n    if (-not [string]::IsNullOrWhiteSpace($VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE)) {\n        Write-Verbose \"Setting 'X-Vault-Namespace' header to: $VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE\"\n        $Headers.Add(\"X-Vault-Namespace\", $VAULT_APPROLE_WRAPPED_SECRETID_NAMESPACE)\n    }\n    \n    $uri = \"$VAULT_APPROLE_WRAPPED_SECRETID_ADDRESS/$VAULT_APPROLE_WRAPPED_SECRETID_API_VERSION/$VAULT_APPROLE_WRAPPED_SECRETID_PATH/role/$([uri]::EscapeDataString($VAULT_APPROLE_WRAPPED_SECRETID_ROLENAME))/secret-id\"\n    Write-Verbose \"Making Put request to $uri\"\n    $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Put\n    \n    if($null -ne $response) {\n    \tSet-OctopusVariable -Name \"WrappedToken\" -Value $response.wrap_info.token -Sensitive\n        Set-OctopusVariable -Name \"WrappedTokenCreationPath\" -Value $response.wrap_info.creation_path -Sensitive\n        Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.WrappedToken}\"\n        Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.WrappedTokenCreationPath}\"\n    }\n    else {\n    \tWrite-Error \"Null or Empty response returned from Vault server\" -Category InvalidResult\n    }\n}\ncatch {\n    $ExceptionMessage = $_.Exception.Message\n    $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n    $Message = \"An error occurred getting a wrapped secretid: $ExceptionMessage\"\n    $AdditionalDetail = \"\"\n    if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n        if ($null -ne $ErrorBody.errors) {\n            $AdditionalDetail = $ErrorBody.errors -Join \",\"   \n        }\n        else {\n            $errorDetails = $null\n            try { $errorDetails = ConvertFrom-Json $ErrorBody } catch {}\n            $AdditionalDetail += if ($null -ne $errorDetails) { $errorDetails.errors -Join \",\" } else { $ErrorBody } \n        }\n    }\n    \n    if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n        $Message += \"`n`tDetail: $AdditionalDetail\"\n    }\n\n    Write-Error $Message -Category ConnectionError\n}"
  },
  "Category": "HashiCorp Vault",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/hashicorp-vault-approle-get-wrapped-secretid.json",
  "Website": "/step-templates/76827264-af27-46d0-913a-e093a4f0db48",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Sunday, September 18, 2022