Get an API Key for the current user?

I have a few runbooks that do specific enough actions with Octopus Deploy that I need to invoke the Octopus Deploy Rest API. Right now I have a service account user that has an API Key that I use to invoke those calls.

But this destroys audit trails. All the actions seem to be done by the service account user.

Is there a way to have a script running in Octopus Deploy get a temporary API Key for the current user? That way the user that executes the runbook gets recorded in the audit trail as the user that made the change.

Hi @OctopusSchaff,

Thanks for reaching out.

To maintain a proper Audit Log that shows which user ran it, I think your best path forward here would be to make the API Key a prompted sensitive variable with no default value, which will force the user to use their own API key which will end up in the Audit Log.

Please let me know if you think that will work for you.

Best,
Jeremy

I think I would rather have the audit trail be useless than have to make my Ops Team be entering API Keys. I was just wondering if I can have the best of both worlds.

I was thinking that Octopus Deploy may have a way to get a token for the user that would somehow be scoped to that script so it cannot use used anywhere else.

If that is not an existing feature, then I will just keep using a service account user.

Hi @OctopusSchaff,

I’m going to have some discussions internally to see if we have other options for your use case.

Please feel free to reach out in the meantime.

Best,
Jeremy

Hi @OctopusSchaff,

The only other solution that would work outside of a prompted sensitive variable API key, would be to create and delete an API key based on the user who clicked run on the runbook.

Step 1 (Create API KEY)
This will use Octopus.Client.dll to create an API key based on the username that ran the runbook. It will create a sensitive output variable that will pass along the newly created API key to the next steps to use. This will show the purpose as the username in the audit log. If you are doing this outside of the default space we will need to modify this script a bit to account for that.

You could also do this with REST if you prefer, an example script you could start with is here: OctopusDeploy-Api/CreateAPIKey.ps1 at master · OctopusDeploy/OctopusDeploy-Api · GitHub. You would make username the owner of the original API key, and the Purpose the same as below, and instead of outputting the API Key, you would create the sensitive variable like below.

Add-Type -Path "C:\Program Files\Octopus Deploy\Octopus\Octopus.Client.dll" #You will need to point to a location on the machine doing the work where Octopus.Client.dll resides

# Define working variables
$octopusURL = "https://"
$octopusAPIKey = "#{APIKey}" #Project Variable of the API Key with privs to do the job
$name = "#{Octopus.Deployment.CreatedBy.DisplayName}" #Gets the Display Name of the user who ran the runbook

# Purpose of the API Key. This field is mandatory.
$APIKeyPurpose = "$($name)" #setting the Purpose of the new API key to the user

$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $octopusURL, $octopusAPIKey
$repository = New-Object Octopus.Client.OctopusRepository $endpoint

try
{
    # Get Current user
    $User = $repository.Users.GetCurrent()

    # Create API Key for user
    $ApiKeyResponse = $repository.Users.CreateApiKey($User, $APIKeyPurpose)

    # Create Output Variable of API Key
    Set-OctopusVariable -name "ApiKey" -value "$($ApiKeyResponse.ApiKey)" -sensitive
}
catch
{
    Write-Host $_.Exception.Message
}

Step 2 (Use API KEY)
In this step, you will just start the script with
$ApiKey = "#{Octopus.Action[StepName_that_created_Api_key].Output.APIKey}" and use the $APIKey variable where applicable to do the work. This is the API Key that has the purpose stated as the User who ran the runbook.

Step 3 (Delete API KEY)
In this step, you will get all API keys for the user that owns the original API Key, parse through them searching for the purpose that matches the user, and delete that API key.

$ApiKey = "#{APIKey}" #Use the original API Key
$OctopusServerUrl = "https://"
$userId = "" #Hardcode the user ID that owns the original API Key such as Users-1
$name = "#{Octopus.Deployment.CreatedBy.DisplayName}" #Get the Puporse search criteria


$apikeys = Invoke-RestMethod -Uri "$OctopusServerUrl/api/users/$($userId)/apikeys" -Headers @{"X-Octopus-ApiKey"="$ApiKey"}

foreach ($api in $apikeys.Items){

if ($api.Purpose -eq "$($name)"){
$apikeyId = $api.Id
}
}

Invoke-RestMethod -Method "DELETE" "$($OctopusServerUrl)/api/users/$($userId)/apikeys/$($apikeyID)" -Headers @{"X-Octopus-ApiKey"="$ApiKey"} 

As always, please read any scripts we give you or suggest thoroughly and test in a test environment before using in production. They are not guaranteed to work in all scenarios.

Please let me know if you think that will fit your use case to get the desired information in your audit log.

Best,
Jeremy

1 Like

That is a good idea. Thanks for putting that together for me!

1 Like

Hey @OctopusSchaff,

You’re very welcome!

I’m glad to hear you think it’ll work for your use case.

Please let me know if you run into any issues with it as I’ll likely keep it in my tool chest for others in the future.

I hope you have a great rest of your week.

Best,
Jeremy