This script uploads a certificate file in pfx format to the Octopus certificate library to be used in deployments or runbooks.
Usage
Provide values for:
- Octopus URL
- Octopus API Key
- PFX file path
- PFX file password
- Certificate Name
Script
PowerShell (REST API)
$ErrorActionPreference = "Stop";
# Define working variables
$octopusURL = "https://your-octopus-url"
$octopusAPIKey = "API-YOUR-KEY"
$header = @{ "X-Octopus-ApiKey" = $octopusAPIKey }
$spaceName = "default"
# Certificate details
$certificateName = "MyCertificate"
$certificateNotes = ""
$certificateFilePath = "path\to\pfx_file.pfx"
$certificatePfxPassword = "PFX-file-password"
$certificateEnvironmentIds = @()
$certificateTenantIds = @()
$certificateTenantTags = @()
$certificateTenantedDeploymentParticipation = "Untenanted"
# Convert PFX file to base64
$certificateContent = [Convert]::ToBase64String((Get-Content -Path $certificateFilePath -Encoding Byte))
# Get space
$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName}
# Create JSON payload
$jsonPayload = @{
Name = $certificateName
Notes = $certificateNotes
certificateData = @{
HasValue = $true
NewValue = $certificateContent
}
password = @{
HasValue = $true
NewValue = $certificatePfxPassword
}
EnvironmentIds = $certificateEnvironmentIds
TenantIds = $certificateTenantIds
TenantTags = $certificateTenantTags
TenantedDeploymentParticipation = $certificateTenantedDeploymentParticipation
}
# Submit request
Invoke-RestMethod -Method Post -Uri "$octopusURL/api/$($space.Id)/certificates" -Body ($jsonPayload | ConvertTo-Json -Depth 10) -Headers $header
PowerShell (Octopus.Client)
# Load Octopus Client assembly
Add-Type -Path 'path\to\Octopus.Client.dll'
# Declare working variables
$octopusURI = 'https://your-octopus-url' # Your server address
$apikey = 'API-YOUR-KEY' # Get this from your profile
$spaceName = 'default'
$endpoint = New-Object Octopus.Client.OctopusServerEndpoint $octopusURI,$apikey
$repository = New-Object Octopus.Client.OctopusRepository $endpoint
$client = New-Object Octopus.Client.OctopusClient $endpoint
try
{
# Get space
$space = $repository.Spaces.FindByName($spaceName)
$repositoryForSpace = $client.ForSpace($space)
# Fill in certificate details
$pfxFilePath = "path\to\pfx_file.pfx" # note: other file formats are supported https://octopus.com/docs/deploying-applications/certificates/file-formats
$pfxBase64 = [Convert]::ToBase64String((Get-Content -Path $pfxFilePath -Encoding Byte))
$pfxPassword = "PFX-file-password"
$certificateName = "MyCertificate" # The display name in Octopus
# Create certificate
$certificateResource = New-Object -TypeName "Octopus.Client.Model.CertificateResource" -ArgumentList @($certificateName, $pfxBase64, $pfxPassword)
$certificateResource = $repositoryForSpace.Certificates.Create($certificateResource);
}
catch
{
Write-Host $_.Exception.Message
}
C#
// If using .net Core, be sure to add the NuGet package of System.Security.Permissions
#r "path\to\Octopus.Client.dll"
using Octopus.Client;
using Octopus.Client.Model;
// Declare working variables
var octopusURL = "https://your-octopus-url";
var octopusAPIKey = "API-YOUR-KEY";
string pfxFilePath = "path\\to\\pfx_file.pfx";
string pfxFilePassword = "PFX-file-password";
string certificateName = "MyCertificate";
string spaceName = "default";
// Create repository object
var endpoint = new OctopusServerEndpoint(octopusURL, octopusAPIKey);
var repository = new OctopusRepository(endpoint);
var client = new OctopusClient(endpoint);
try
{
// Get space
var space = repository.Spaces.FindByName(spaceName);
var repositoryForSpace = client.ForSpace(space);
// Convert file to base64
string base64Certificate = Convert.ToBase64String(System.IO.File.ReadAllBytes(pfxFilePath));
// Create certificate object
Octopus.Client.Model.CertificateResource octopusCertificate = new CertificateResource(certificateName, base64Certificate, pfxFilePassword);
repositoryForSpace.Certificates.Create(octopusCertificate);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
Python3
import json
import requests
import base64
octopus_server_uri = 'https://your-octopus-url/api'
octopus_api_key = 'API-YOUR-KEY'
headers = {'X-Octopus-ApiKey': octopus_api_key}
def get_octopus_resource(uri):
response = requests.get(uri, headers=headers)
response.raise_for_status()
return json.loads(response.content.decode('utf-8'))
def get_by_name(uri, name):
resources = get_octopus_resource(uri)
return next((x for x in resources if x['Name'] == name), None)
space_name = 'Default'
certificate_name = 'My Certificate'
certificate_notes = 'My certificate created using python via the REST API'
certificate_file_path = '/path/to/pfx_file.pfx'
certificate_file_password = 'pfx-file-password'
# Optional tenanted parameters
# Use 'Untenanted' for certificate_tenanted_deployment if multi-tenancy not required.
certificate_environments = ['Development']
certificate_tenants = ['Tenant A']
certificate_tenant_tags = ['Upgrade Ring/Stable']
certificate_tenanted_deployment = 'Tenanted'
certificate_data = open(certificate_file_path, 'rb').read()
certificate_base64 = base64.b64encode(certificate_data)
certificate_base64 = str(certificate_base64, 'utf-8')
space = get_by_name('{0}/spaces/all'.format(octopus_server_uri), space_name)
environments = get_octopus_resource('{0}/{1}/environments/all'.format(octopus_server_uri, space['Id']))
environment_ids = [environment['Id'] for environment in environments if environment['Name'] in certificate_environments]
tenants = get_octopus_resource('{0}/{1}/tenants/all'.format(octopus_server_uri, space['Id']))
tenant_ids = [tenant['Id'] for tenant in tenants if tenant['Name'] in certificate_tenants]
certificate = {
'Name': certificate_name,
'Notes': certificate_notes,
'certificateData': {
'HasValue': True,
'NewValue': certificate_base64
},
'password': {
'HasValue': True,
'NewValue': certificate_file_password
},
'EnvironmentIds': environment_ids,
'TenantIds': tenant_ids,
'TenantTags': certificate_tenant_tags,
'TenantedDeploymentParticipation': certificate_tenanted_deployment
}
uri = '{0}/{1}/certificates'.format(octopus_server_uri, space['Id'])
response = requests.post(uri, headers=headers, json=certificate)
response.raise_for_status()
Go
package main
import (
"fmt"
"log"
"net/url"
b64 "encoding/base64"
"io/ioutil"
"github.com/OctopusDeploy/go-octopusdeploy/octopusdeploy"
)
func main() {
apiURL, err := url.Parse("https://your-octopus-url")
if err != nil {
log.Println(err)
}
APIKey := "API-YOUR-KEY"
spaceName := "Default"
certificateName := "MyCertificate"
pathToCertificate := "path:\\To\\PFXFile.pfx"
pfxPassword := "YourPassword"
rawData, err := ioutil.ReadFile(pathToCertificate)
if err != nil {
log.Println(err)
}
// Convert byte array to base 64 string
stringRawData := b64.StdEncoding.EncodeToString([]byte(rawData))
// Create new certificate sensitive value
certificateData := octopusdeploy.SensitiveValue{
HasValue: true,
NewValue: &stringRawData,
}
// Create PFX Password as sensitive value
sensitivePfxPassword := octopusdeploy.SensitiveValue{
HasValue: true,
NewValue: &pfxPassword,
}
// Create new certificate resource
certificate := octopusdeploy.NewCertificateResource(certificateName, &certificateData, &sensitivePfxPassword)
// Get space
space := GetSpace(apiURL, APIKey, spaceName)
// Create client
client := octopusAuth(apiURL, APIKey, space.ID)
// Create certificate
certificate, err = client.Certificates.Add(certificate)
if err != nil {
log.Println(err)
}
}
func octopusAuth(octopusURL *url.URL, APIKey, space string) *octopusdeploy.Client {
client, err := octopusdeploy.NewClient(nil, octopusURL, APIKey, space)
if err != nil {
log.Println(err)
}
return client
}
func GetSpace(octopusURL *url.URL, APIKey string, spaceName string) *octopusdeploy.Space {
client := octopusAuth(octopusURL, APIKey, "")
spaceQuery := octopusdeploy.SpacesQuery{
Name: spaceName,
}
// Get specific space object
spaces, err := client.Spaces.Get(spaceQuery)
if err != nil {
log.Println(err)
}
for _, space := range spaces.Items {
if space.Name == spaceName {
return space
}
}
return nil
}
Help us continuously improve
Please let us know if you have any feedback about this page.
Page updated on Sunday, January 1, 2023