Octopus.Script exported 2024-08-01 by harrisonmeister belongs to ‘Lets Encrypt’ category.
Request (or renew) a X.509 SSL Certificate from the Let’s Encrypt Certificate Authority.
Features
- ACME v2 protocol support which allows generating wildcard certificates (*.example.com)
- DNSimple Challenge for TLD, CNAME and Wildcard domains.
- Publishes/Updates SSL Certificates in the Octopus Deploy Certificate Store.
- Verified to work on both Windows (PowerShell 5+) and Linux (PowerShell 6+) deployment Targets or Workers.
Parameters
When steps based on the template are included in a project’s deployment process, the parameters below can be set.
Certificate Domain
LE_DNSimple_CertificateDomain =
Domain (TLD, CNAME or Wildcard) to create a certificate for.
PFX Password
LE_DNSimple_PfxPassword =
Password to use when converting to / from PFX.
Replace expiring certificate before N days
LE_DNSimple_ReplaceIfExpiresInDays = 30
Replace the certificate if it expiries within N days
Octopus Deploy API key
LE_DNSimple_Octopus_APIKey =
A Octopus Deploy API key with access to change Certificates in the Certificate Store.
Use Lets Encrypt Staging
LE_DNSimple_Use_Staging = false
Should the Certificate be generated using the Lets Encrypt Staging infrastructure?
Contact Email Address
LE_DNSimple_ContactEmailAddress = #{Octopus.Deployment.CreatedBy.EmailAddress}
Email Address
Debug Output
LE_DNSimple_Debug_Output = false
Tick this to provide debug information in the output
Create Wildcard SAN
LE_DNSimple_CreateWildcardSAN = false
Should the certificate have a Subject Alternative Name (SAN) excluding the wildcard?
e.g. a certificate domain of *.internal.example-domain.com
could also have a SAN of internal.example-domain.com
Script body
Steps based on this template will execute the following PowerShell script.
###############################################################################
# TLS 1.2
###############################################################################
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
###############################################################################
# Required Modules folder
###############################################################################
Write-Host "Checking for required powershell modules folder"
$ModulesFolder = "$HOME\Documents\WindowsPowerShell\Modules"
if ($PSEdition -eq "Core") {
if ($PSVersionTable.Platform -eq "Unix") {
$ModulesFolder = "$HOME/.local/share/powershell/Modules"
}
else {
$ModulesFolder = "$HOME\Documents\PowerShell\Modules"
}
}
$PSModuleFolderExists = (Test-Path $ModulesFolder)
if ($PSModuleFolderExists -eq $False) {
Write-Host "Creating directory: $ModulesFolder"
New-Item $ModulesFolder -ItemType Directory -Force
$env:PSModulePath = $ModulesFolder + [System.IO.Path]::PathSeparator + $env:PSModulePath
}
###############################################################################
# Required Modules
###############################################################################
Write-Host "Checking for required modules."
$required_posh_acme_version = 3.12.0
$module_check = Get-Module -ListAvailable -Name Posh-Acme | Where-Object { $_.Version -ge $required_posh_acme_version }
if (-not ($module_check)) {
Write-Host "Ensuring NuGet provider is bootstrapped."
Get-PackageProvider NuGet -ForceBootstrap | Out-Null
Write-Host "Installing Posh-ACME."
Install-Module -Name Posh-ACME -MinimumVersion 3.12.0 -Scope CurrentUser -Force
}
Import-Module Posh-ACME
###############################################################################
# DebugOutput
###############################################################################
if ($OctopusParameters["LE_DNSimple_Debug_Output"] -eq $True) {
Write-Host "Setting DebugPreference to Continue"
$DebugPreference = 'Continue'
}
###############################################################################
# Constants
###############################################################################
$LE_DNSimple_CertificateDomain = $OctopusParameters["LE_DNSimple_CertificateDomain"]
$LE_DNSimple_CertificateName = "Lets Encrypt - $($LE_DNSimple_CertificateDomain)"
# Issuer used in a cert could be one of multiple, including ones no longer supported by Let's Encrypt
$LE_DNSimple_Fake_Issuers = @("Fake LE Intermediate X1", "(STAGING) Artificial Apricot R3", "(STAGING) Ersatz Edamame E1", "(STAGING) Pseudo Plum E5", "(STAGING) False Fennel E6", "(STAGING) Puzzling Parsnip E7", "(STAGING) Mysterious Mulberry E8", "(STAGING) Fake Fig E9", "(STAGING) Counterfeit Cashew R10", "(STAGING) Wannabe Watercress R11", "(STAGING) Riddling Rhubarb R12", "(STAGING) Tenuous Tomato R13", "(STAGING) Not Nectarine R14")
$LE_DNSimple_Issuers = @("Let's Encrypt Authority X3", "E1", "E2", "R3", "R4", "R5", "R6", "R10", "R11")
###############################################################################
# Helpers
###############################################################################
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()
$response = $reader.ReadToEnd()
return $response | ConvertFrom-Json
}
}
else {
return $RequestError.ErrorDetails.Message
}
}
###############################################################################
# Functions
###############################################################################
function Get-LetsEncryptCertificate {
Write-Debug "Entering: Get-LetsEncryptCertificate"
if ($OctopusParameters["LE_DNSimple_Use_Staging"] -eq $True) {
Write-Host "Using Lets Encrypt Server: Staging"
Set-PAServer LE_STAGE;
}
else {
Write-Host "Using Lets Encrypt Server: Production"
Set-PAServer LE_PROD;
}
# Clobber account if it exists.
$le_account = Get-PAAccount
if ($le_account) {
Remove-PAAccount $le_account.Id -Force
}
$dnsimple_args = @{}
# DNSimple requires a token. If it's windows, Secure-String is supported.
if ($IsWindows -and 'Desktop' -eq $PSEdition) {
$token = ConvertTo-SecureString -String $OctopusParameters["LE_DNSimple_Token"] -AsPlainText -Force
$dnsimple_args = @{
DSToken = $token
}
}
else {
$token = $OctopusParameters["LE_DNSimple_Token"]
$dnsimple_args = @{
DSTokenInsecure = $token
}
}
try {
$DnsPlugins = @("DNSimple")
$DomainList = @($LE_DNSimple_CertificateDomain)
# If domain is a wildcard e.g. *.example-domain.com, check if a SAN has been requested e.g. example-domain.com.
if ($LE_DNSimple_CertificateDomain -match "\*." -and $OctopusParameters["LE_DNSimple_CreateWildcardSAN"] -eq $True) {
$LE_DNSimple_Certificate_SAN = $LE_DNSimple_CertificateDomain.Replace("*.","")
$DomainList += $LE_DNSimple_Certificate_SAN
# Include additional DnsPlugin of same type to surpress warning.
$DnsPlugins += "DNSimple"
}
$Cert_Params = @{
Domain = $DomainList
AcceptTOS = $True;
Contact = $OctopusParameters["LE_DNSimple_ContactEmailAddress"];
DnsPlugin = $DnsPlugins;
PluginArgs = $dnsimple_args;
PfxPass = $OctopusParameters["LE_DNSimple_PfxPassword"];
Force = $True;
}
return New-PACertificate @Cert_Params
}
catch {
Write-Host "Failed to Create Certificate. Error Message: $($_.Exception.Message). See Debug output for details."
Write-Debug (Get-WebRequestErrorBody -RequestError $_)
exit 1
}
}
function Get-OctopusCertificates {
Write-Debug "Entering: Get-OctopusCertificates"
$octopus_uri = $OctopusParameters["Octopus.Web.ServerUri"]
$octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
$octopus_headers = @{ "X-Octopus-ApiKey" = $OctopusParameters["LE_DNSimple_Octopus_APIKey"] }
$octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates?search=$($LE_DNSimple_CertificateDomain)"
try {
# Get a list of certificates that match our domain search criteria.
$certificates_search = Invoke-WebRequest -Uri $octopus_certificates_uri -Method Get -Headers $octopus_headers -UseBasicParsing -ErrorAction Stop | ConvertFrom-Json | Select-Object -ExpandProperty Items
# We don't want to confuse Production and Staging Lets Encrypt Certificates.
$possible_issuers = $LE_DNSimple_Issuers
if ($OctopusParameters["LE_DNSimple_Use_Staging"] -eq $True) {
$possible_issuers = $LE_DNSimple_Fake_Issuers
}
return $certificates_search | Where-Object {
$_.SubjectCommonName -eq $LE_DNSimple_CertificateDomain -and
$possible_issuers -contains $_.IssuerCommonName -and
$null -eq $_.ReplacedBy -and
$null -eq $_.Archived
}
}
catch {
Write-Host "Could not retrieve certificates from Octopus Deploy. Error: $($_.Exception.Message). See Debug output for details."
Write-Debug (Get-WebRequestErrorBody -RequestError $_)
exit 1
}
}
function Publish-OctopusCertificate {
param (
[string] $JsonBody
)
Write-Debug "Entering: Publish-OctopusCertificate"
if (-not ($JsonBody)) {
Write-Host "Existing Certificate is required."
exit 1
}
$octopus_uri = $OctopusParameters["Octopus.Web.ServerUri"]
$octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
$octopus_headers = @{ "X-Octopus-ApiKey" = $OctopusParameters["LE_DNSimple_Octopus_APIKey"] }
$octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates"
try {
Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing
Write-Host "Published $($LE_DNSimple_CertificateDomain) certificate to the Octopus Deploy Certificate Store."
}
catch {
Write-Host "Failed to publish $($LE_DNSimple_CertificateDomain) certificate. Error: $($_.Exception.Message). See Debug output for details."
Write-Debug (Get-WebRequestErrorBody -RequestError $_)
exit 1
}
}
function Update-OctopusCertificate {
param (
[string]$Certificate_Id,
[string]$JsonBody
)
Write-Debug "Entering: Update-OctopusCertificate"
if (-not ($Certificate_Id -and $JsonBody)) {
Write-Host "Existing Certificate Id and a replace Certificate are required."
exit 1
}
$octopus_uri = $OctopusParameters["Octopus.Web.ServerUri"]
$octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
$octopus_headers = @{ "X-Octopus-ApiKey" = $OctopusParameters["LE_DNSimple_Octopus_APIKey"] }
$octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates/$Certificate_Id/replace"
try {
Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing
Write-Host "Replaced $($LE_DNSimple_CertificateDomain) certificate in the Octopus Deploy Certificate Store."
}
catch {
Write-Error "Failed to replace $($LE_DNSimple_CertificateDomain) certificate. Error: $($_.Exception.Message)"
exit 1
}
}
function Get-NewCertificatePFXAsJson {
param (
$Certificate
)
Write-Debug "Entering: Get-NewCertificatePFXAsJson"
if (-not ($Certificate)) {
Write-Host "Certificate is required."
Exit 1
}
[Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($Certificate.PfxFullChain)
$certificate_base64 = [convert]::ToBase64String($certificate_buffer)
$certificate_body = @{
Name = "$LE_DNSimple_CertificateName";
Notes = "";
CertificateData = @{
HasValue = $true;
NewValue = $certificate_base64;
};
Password = @{
HasValue = $true;
NewValue = $OctopusParameters["LE_DNSimple_PfxPassword"];
};
}
return $certificate_body | ConvertTo-Json
}
function Get-ReplaceCertificatePFXAsJson {
param (
$Certificate
)
Write-Debug "Entering: Get-ReplaceCertificatePFXAsJson"
if (-not ($Certificate)) {
Write-Host "Certificate is required."
Exit 1
}
[Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($Certificate.PfxFullChain)
$certificate_base64 = [convert]::ToBase64String($certificate_buffer)
$certificate_body = @{
CertificateData = $certificate_base64;
Password = $OctopusParameters["LE_DNSimple_PfxPassword"];
}
return $certificate_body | ConvertTo-Json
}
###############################################################################
# DO THE THING | MAIN |
###############################################################################
Write-Debug "Do the Thing"
Write-Host "Checking for existing Lets Encrypt Certificates in the Octopus Deploy Certificates Store."
$certificates = Get-OctopusCertificates
# Check for PFX & PEM
if ($certificates) {
# Handle weird behavior between Powershell 5 and Powershell 6+
$certificate_count = 1
if ($certificates.Count -ge 1) {
$certificate_count = $certificates.Count
}
Write-Host "Found $certificate_count for $($LE_DNSimple_CertificateDomain)."
Write-Host "Checking to see if any expire within $($OctopusParameters["LE_DNSimple_ReplaceIfExpiresInDays"]) days."
# Check Expiry Dates
$expiring_certificates = $certificates | Where-Object { [DateTime]$_.NotAfter -lt (Get-Date).AddDays($OctopusParameters["LE_DNSimple_ReplaceIfExpiresInDays"]) }
if ($expiring_certificates) {
Write-Host "Found certificates that expire with $($OctopusParameters["LE_DNSimple_ReplaceIfExpiresInDays"]) days. Requesting new certificates for $($LE_DNSimple_CertificateDomain) from Lets Encrypt"
$le_certificate = Get-LetsEncryptCertificate
# PFX
$existing_certificate = $certificates | Where-Object { $_.CertificateDataFormat -eq "Pkcs12" } | Select-Object -First 1
$certificate_as_json = Get-ReplaceCertificatePFXAsJson -Certificate $le_certificate
Update-OctopusCertificate -Certificate_Id $existing_certificate.Id -JsonBody $certificate_as_json
}
else {
Write-Host "Nothing to do here..."
}
exit 0
}
# No existing Certificates - Lets get some new ones.
Write-Host "No existing certificates found for $($LE_DNSimple_CertificateDomain)."
Write-Host "Request New Certificate for $($LE_DNSimple_CertificateDomain) from Lets Encrypt"
# New Certificate..
$le_certificate = Get-LetsEncryptCertificate
Write-Host "Publishing: LetsEncrypt - $($LE_DNSimple_CertificateDomain) (PFX)"
$certificate_as_json = Get-NewCertificatePFXAsJson -Certificate $le_certificate
Publish-OctopusCertificate -JsonBody $certificate_as_json
Write-Host "GREAT SUCCESS"
Provided under the Apache License version 2.0.
To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.
{
"Id": "21583723-1283-46aa-bb7b-121d365837cb",
"Name": "Lets Encrypt - DNSimple",
"Description": "Request (or renew) a X.509 SSL Certificate from the [Let's Encrypt Certificate Authority](https://letsencrypt.org/). \n\n#### Features\n\n- ACME v2 protocol support which allows generating wildcard certificates (*.example.com)\n- [DNSimple](https://dnsimple.com/) Challenge for TLD, CNAME and Wildcard domains. \n- Publishes/Updates SSL Certificates in the [Octopus Deploy Certificate Store](https://octopus.com/docs/deployment-examples/certificates). \n- Verified to work on both Windows (PowerShell 5+) and Linux (PowerShell 6+) deployment Targets or Workers.",
"Version": 8,
"ExportedAt": "2024-08-01T10:57:00.608Z",
"ActionType": "Octopus.Script",
"Author": "harrisonmeister",
"Packages": [],
"Parameters": [
{
"Id": "d0984e44-0783-4ddc-8a57-8008997edb2a",
"Name": "LE_DNSimple_CertificateDomain",
"Label": "Certificate Domain",
"HelpText": "Domain (TLD, CNAME or Wildcard) to create a certificate for. ",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "c68389d4-17e4-491b-a6ce-ee6b09ae1579",
"Name": "LE_DNSimple_PfxPassword",
"Label": "PFX Password",
"HelpText": "Password to use when converting to / from PFX. ",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "0bce1a67-4981-474d-8b93-873fa3b28712",
"Name": "LE_DNSimple_ReplaceIfExpiresInDays",
"Label": "Replace expiring certificate before N days",
"HelpText": "Replace the certificate if it expiries within N days",
"DefaultValue": "30",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "f1f25997-9733-4882-a546-ef6c76b7c7f1",
"Name": "LE_DNSimple_Token",
"Label": "DNSimple API Token",
"HelpText": "DNSimple API Token created from your [DNSimple account](https://github.com/rmbolger/Posh-ACME/blob/master/Posh-ACME/DnsPlugins/DNSimple-Readme.md#setup)",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "1addd2e6-782d-4a1f-bd12-480a9dd964cd",
"Name": "LE_DNSimple_Octopus_APIKey",
"Label": "Octopus Deploy API key",
"HelpText": "A Octopus Deploy API key with access to change Certificates in the Certificate Store. ",
"DefaultValue": "",
"DisplaySettings": {
"Octopus.ControlType": "Sensitive"
}
},
{
"Id": "ad07684b-93ea-4d65-b2a8-395e3bbfdaf8",
"Name": "LE_DNSimple_Use_Staging",
"Label": "Use Lets Encrypt Staging",
"HelpText": "Should the Certificate be generated using the Lets Encrypt Staging infrastructure?",
"DefaultValue": "false",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "9a358e2e-07df-42d1-9f0a-04cbc800dacf",
"Name": "LE_DNSimple_ContactEmailAddress",
"Label": "Contact Email Address",
"HelpText": "Email Address",
"DefaultValue": "#{Octopus.Deployment.CreatedBy.EmailAddress}",
"DisplaySettings": {
"Octopus.ControlType": "SingleLineText"
}
},
{
"Id": "3a9e5773-9fbb-4dd4-a9c2-0f66a36b74a2",
"Name": "LE_DNSimple_Debug_Output",
"Label": "Debug Output",
"HelpText": "Tick this to provide debug information in the output",
"DefaultValue": "false",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
},
{
"Id": "2dc7d9bc-9eee-4ee0-a33c-ef9371ed69f1",
"Name": "LE_DNSimple_CreateWildcardSAN",
"Label": "Create Wildcard SAN",
"HelpText": "Should the certificate have a Subject Alternative Name (SAN) excluding the wildcard?\n\ne.g. a certificate domain of `*.internal.example-domain.com` could also have a SAN of `internal.example-domain.com`",
"DefaultValue": "false",
"DisplaySettings": {
"Octopus.ControlType": "Checkbox"
}
}
],
"Properties": {
"Octopus.Action.Script.ScriptSource": "Inline",
"Octopus.Action.Script.Syntax": "PowerShell",
"Octopus.Action.Script.ScriptBody": "###############################################################################\n# TLS 1.2\n###############################################################################\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\n###############################################################################\n# Required Modules folder\n###############################################################################\nWrite-Host \"Checking for required powershell modules folder\"\n$ModulesFolder = \"$HOME\\Documents\\WindowsPowerShell\\Modules\"\nif ($PSEdition -eq \"Core\") {\n if ($PSVersionTable.Platform -eq \"Unix\") {\n $ModulesFolder = \"$HOME/.local/share/powershell/Modules\"\n }\n else {\n $ModulesFolder = \"$HOME\\Documents\\PowerShell\\Modules\"\n }\n}\n$PSModuleFolderExists = (Test-Path $ModulesFolder)\nif ($PSModuleFolderExists -eq $False) {\n\tWrite-Host \"Creating directory: $ModulesFolder\"\n\tNew-Item $ModulesFolder -ItemType Directory -Force\n $env:PSModulePath = $ModulesFolder + [System.IO.Path]::PathSeparator + $env:PSModulePath\n}\n\n###############################################################################\n# Required Modules\n###############################################################################\nWrite-Host \"Checking for required modules.\"\n$required_posh_acme_version = 3.12.0\n$module_check = Get-Module -ListAvailable -Name Posh-Acme | Where-Object { $_.Version -ge $required_posh_acme_version }\n\nif (-not ($module_check)) {\n Write-Host \"Ensuring NuGet provider is bootstrapped.\"\n Get-PackageProvider NuGet -ForceBootstrap | Out-Null\n Write-Host \"Installing Posh-ACME.\"\n Install-Module -Name Posh-ACME -MinimumVersion 3.12.0 -Scope CurrentUser -Force\n}\n\nImport-Module Posh-ACME\n\n###############################################################################\n# DebugOutput\n###############################################################################\nif ($OctopusParameters[\"LE_DNSimple_Debug_Output\"] -eq $True) {\n\tWrite-Host \"Setting DebugPreference to Continue\"\n $DebugPreference = 'Continue'\n}\n\n###############################################################################\n# Constants\n###############################################################################\n$LE_DNSimple_CertificateDomain = $OctopusParameters[\"LE_DNSimple_CertificateDomain\"]\n$LE_DNSimple_CertificateName = \"Lets Encrypt - $($LE_DNSimple_CertificateDomain)\"\n\n# Issuer used in a cert could be one of multiple, including ones no longer supported by Let's Encrypt\n$LE_DNSimple_Fake_Issuers = @(\"Fake LE Intermediate X1\", \"(STAGING) Artificial Apricot R3\", \"(STAGING) Ersatz Edamame E1\", \"(STAGING) Pseudo Plum E5\", \"(STAGING) False Fennel E6\", \"(STAGING) Puzzling Parsnip E7\", \"(STAGING) Mysterious Mulberry E8\", \"(STAGING) Fake Fig E9\", \"(STAGING) Counterfeit Cashew R10\", \"(STAGING) Wannabe Watercress R11\", \"(STAGING) Riddling Rhubarb R12\", \"(STAGING) Tenuous Tomato R13\", \"(STAGING) Not Nectarine R14\")\n$LE_DNSimple_Issuers = @(\"Let's Encrypt Authority X3\", \"E1\", \"E2\", \"R3\", \"R4\", \"R5\", \"R6\", \"R10\", \"R11\")\n\n\n###############################################################################\n# Helpers\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 $response = $reader.ReadToEnd()\n\n return $response | ConvertFrom-Json\n }\n }\n else {\n return $RequestError.ErrorDetails.Message\n }\n}\n\n###############################################################################\n# Functions\n###############################################################################\nfunction Get-LetsEncryptCertificate {\n Write-Debug \"Entering: Get-LetsEncryptCertificate\"\n\n if ($OctopusParameters[\"LE_DNSimple_Use_Staging\"] -eq $True) {\n Write-Host \"Using Lets Encrypt Server: Staging\"\n Set-PAServer LE_STAGE;\n }\n else {\n Write-Host \"Using Lets Encrypt Server: Production\"\n Set-PAServer LE_PROD;\n }\n\n # Clobber account if it exists.\n $le_account = Get-PAAccount\n if ($le_account) {\n Remove-PAAccount $le_account.Id -Force\n }\n\n\t$dnsimple_args = @{}\n # DNSimple requires a token. If it's windows, Secure-String is supported.\n if ($IsWindows -and 'Desktop' -eq $PSEdition) {\n $token = ConvertTo-SecureString -String $OctopusParameters[\"LE_DNSimple_Token\"] -AsPlainText -Force\n \t$dnsimple_args = @{\n \tDSToken = $token\n \t}\n }\n else {\n \t$token = $OctopusParameters[\"LE_DNSimple_Token\"]\n \t$dnsimple_args = @{\n \tDSTokenInsecure = $token\n \t}\n }\n \n try {\n\n $DnsPlugins = @(\"DNSimple\")\n $DomainList = @($LE_DNSimple_CertificateDomain)\n \n # If domain is a wildcard e.g. *.example-domain.com, check if a SAN has been requested e.g. example-domain.com.\n if ($LE_DNSimple_CertificateDomain -match \"\\*.\" -and $OctopusParameters[\"LE_DNSimple_CreateWildcardSAN\"] -eq $True) {\n $LE_DNSimple_Certificate_SAN = $LE_DNSimple_CertificateDomain.Replace(\"*.\",\"\")\n $DomainList += $LE_DNSimple_Certificate_SAN\n # Include additional DnsPlugin of same type to surpress warning.\n $DnsPlugins += \"DNSimple\"\n }\n\n $Cert_Params = @{\n Domain = $DomainList\n AcceptTOS = $True;\n Contact = $OctopusParameters[\"LE_DNSimple_ContactEmailAddress\"];\n DnsPlugin = $DnsPlugins;\n PluginArgs = $dnsimple_args;\n PfxPass = $OctopusParameters[\"LE_DNSimple_PfxPassword\"];\n Force = $True;\n }\n\n return New-PACertificate @Cert_Params\n }\n catch {\n Write-Host \"Failed to Create Certificate. Error Message: $($_.Exception.Message). See Debug output for details.\"\n Write-Debug (Get-WebRequestErrorBody -RequestError $_)\n exit 1\n }\n}\n\nfunction Get-OctopusCertificates {\n Write-Debug \"Entering: Get-OctopusCertificates\"\n\n $octopus_uri = $OctopusParameters[\"Octopus.Web.ServerUri\"]\n $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n $octopus_headers = @{ \"X-Octopus-ApiKey\" = $OctopusParameters[\"LE_DNSimple_Octopus_APIKey\"] }\n $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates?search=$($LE_DNSimple_CertificateDomain)\"\n\n try {\n # Get a list of certificates that match our domain search criteria.\n $certificates_search = Invoke-WebRequest -Uri $octopus_certificates_uri -Method Get -Headers $octopus_headers -UseBasicParsing -ErrorAction Stop | ConvertFrom-Json | Select-Object -ExpandProperty Items\n\n # We don't want to confuse Production and Staging Lets Encrypt Certificates.\n $possible_issuers = $LE_DNSimple_Issuers\n if ($OctopusParameters[\"LE_DNSimple_Use_Staging\"] -eq $True) {\n $possible_issuers = $LE_DNSimple_Fake_Issuers\n }\n\n return $certificates_search | Where-Object {\n $_.SubjectCommonName -eq $LE_DNSimple_CertificateDomain -and\n $possible_issuers -contains $_.IssuerCommonName -and\n $null -eq $_.ReplacedBy -and\n $null -eq $_.Archived\n }\n }\n catch {\n Write-Host \"Could not retrieve certificates from Octopus Deploy. Error: $($_.Exception.Message). See Debug output for details.\"\n Write-Debug (Get-WebRequestErrorBody -RequestError $_)\n exit 1\n }\n}\n\nfunction Publish-OctopusCertificate {\n param (\n [string] $JsonBody\n )\n\n Write-Debug \"Entering: Publish-OctopusCertificate\"\n\n if (-not ($JsonBody)) {\n Write-Host \"Existing Certificate is required.\"\n exit 1\n }\n\n $octopus_uri = $OctopusParameters[\"Octopus.Web.ServerUri\"]\n $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n $octopus_headers = @{ \"X-Octopus-ApiKey\" = $OctopusParameters[\"LE_DNSimple_Octopus_APIKey\"] }\n $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates\"\n\n try {\n Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing\n Write-Host \"Published $($LE_DNSimple_CertificateDomain) certificate to the Octopus Deploy Certificate Store.\"\n }\n catch {\n Write-Host \"Failed to publish $($LE_DNSimple_CertificateDomain) certificate. Error: $($_.Exception.Message). See Debug output for details.\"\n Write-Debug (Get-WebRequestErrorBody -RequestError $_)\n exit 1\n }\n}\n\nfunction Update-OctopusCertificate {\n param (\n [string]$Certificate_Id,\n [string]$JsonBody\n )\n\n Write-Debug \"Entering: Update-OctopusCertificate\"\n\n if (-not ($Certificate_Id -and $JsonBody)) {\n Write-Host \"Existing Certificate Id and a replace Certificate are required.\"\n exit 1\n }\n\n $octopus_uri = $OctopusParameters[\"Octopus.Web.ServerUri\"]\n $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n $octopus_headers = @{ \"X-Octopus-ApiKey\" = $OctopusParameters[\"LE_DNSimple_Octopus_APIKey\"] }\n $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates/$Certificate_Id/replace\"\n\n try {\n Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing\n Write-Host \"Replaced $($LE_DNSimple_CertificateDomain) certificate in the Octopus Deploy Certificate Store.\"\n }\n catch {\n Write-Error \"Failed to replace $($LE_DNSimple_CertificateDomain) certificate. Error: $($_.Exception.Message)\"\n exit 1\n }\n}\n\nfunction Get-NewCertificatePFXAsJson {\n param (\n $Certificate\n )\n\n Write-Debug \"Entering: Get-NewCertificatePFXAsJson\"\n\n if (-not ($Certificate)) {\n Write-Host \"Certificate is required.\"\n Exit 1\n }\n\n [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($Certificate.PfxFullChain)\n $certificate_base64 = [convert]::ToBase64String($certificate_buffer)\n\n $certificate_body = @{\n Name = \"$LE_DNSimple_CertificateName\";\n Notes = \"\";\n CertificateData = @{\n HasValue = $true;\n NewValue = $certificate_base64;\n };\n Password = @{\n HasValue = $true;\n NewValue = $OctopusParameters[\"LE_DNSimple_PfxPassword\"];\n };\n }\n\n return $certificate_body | ConvertTo-Json\n}\n\nfunction Get-ReplaceCertificatePFXAsJson {\n param (\n $Certificate\n )\n\n Write-Debug \"Entering: Get-ReplaceCertificatePFXAsJson\"\n\n if (-not ($Certificate)) {\n Write-Host \"Certificate is required.\"\n Exit 1\n }\n\n [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($Certificate.PfxFullChain)\n $certificate_base64 = [convert]::ToBase64String($certificate_buffer)\n\n $certificate_body = @{\n CertificateData = $certificate_base64;\n Password = $OctopusParameters[\"LE_DNSimple_PfxPassword\"];\n }\n\n return $certificate_body | ConvertTo-Json\n}\n\n###############################################################################\n# DO THE THING | MAIN |\n###############################################################################\nWrite-Debug \"Do the Thing\"\n\nWrite-Host \"Checking for existing Lets Encrypt Certificates in the Octopus Deploy Certificates Store.\"\n$certificates = Get-OctopusCertificates\n\n# Check for PFX & PEM\nif ($certificates) {\n\n # Handle weird behavior between Powershell 5 and Powershell 6+\n $certificate_count = 1\n if ($certificates.Count -ge 1) {\n $certificate_count = $certificates.Count\n }\n\n Write-Host \"Found $certificate_count for $($LE_DNSimple_CertificateDomain).\"\n Write-Host \"Checking to see if any expire within $($OctopusParameters[\"LE_DNSimple_ReplaceIfExpiresInDays\"]) days.\"\n\n # Check Expiry Dates\n $expiring_certificates = $certificates | Where-Object { [DateTime]$_.NotAfter -lt (Get-Date).AddDays($OctopusParameters[\"LE_DNSimple_ReplaceIfExpiresInDays\"]) }\n\n if ($expiring_certificates) {\n Write-Host \"Found certificates that expire with $($OctopusParameters[\"LE_DNSimple_ReplaceIfExpiresInDays\"]) days. Requesting new certificates for $($LE_DNSimple_CertificateDomain) from Lets Encrypt\"\n $le_certificate = Get-LetsEncryptCertificate\n\n # PFX\n $existing_certificate = $certificates | Where-Object { $_.CertificateDataFormat -eq \"Pkcs12\" } | Select-Object -First 1\n $certificate_as_json = Get-ReplaceCertificatePFXAsJson -Certificate $le_certificate\n Update-OctopusCertificate -Certificate_Id $existing_certificate.Id -JsonBody $certificate_as_json\n }\n else {\n Write-Host \"Nothing to do here...\"\n }\n\n exit 0\n}\n\n# No existing Certificates - Lets get some new ones.\nWrite-Host \"No existing certificates found for $($LE_DNSimple_CertificateDomain).\"\nWrite-Host \"Request New Certificate for $($LE_DNSimple_CertificateDomain) from Lets Encrypt\"\n\n# New Certificate..\n$le_certificate = Get-LetsEncryptCertificate\n\nWrite-Host \"Publishing: LetsEncrypt - $($LE_DNSimple_CertificateDomain) (PFX)\"\n$certificate_as_json = Get-NewCertificatePFXAsJson -Certificate $le_certificate\nPublish-OctopusCertificate -JsonBody $certificate_as_json\n\nWrite-Host \"GREAT SUCCESS\"\n",
"Octopus.Action.SubstituteInFiles.Enabled": "True"
},
"Category": "Lets Encrypt",
"HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/letsencrypt-dnsimple.json",
"Website": "/step-templates/21583723-1283-46aa-bb7b-121d365837cb",
"Logo": "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",
"$Meta": {
"Type": "ActionTemplate"
}
}
Page updated on Thursday, August 1, 2024