Lets Encrypt - Self-Hosted HTTP Challenge

Octopus.Script exported 2024-08-01 by harrisonmeister belongs to ‘Lets Encrypt’ category.

Request (or renew) an X.509 SSL Certificate from the Let’s Encrypt Certificate Authority using the Self-hosted HTTP Challenge Listener provided by the Posh-ACME PowerShell Module.


Please Note

It’s generally a better idea to use one of the Posh-ACME DNS providers for Let’s Encrypt.

There are a number of Octopus Step templates in the Community Library that support DNS providers.


Features

  • ACME v2 protocol support which allows generating wildcard certificates (*.example.com).
  • Self-hosted HTTP Challenge Challenge for TLD, CNAME, and Wildcard domains.
  • Optionally Publishes/Updates SSL Certificates in the Octopus Deploy Certificate Store.
  • Optionally import SSL Certificate into the local machine store.
  • Optionally Export PFX (PKCS#12) SSL Certificate to a supplied file path.
  • Verified to work on Windows and Linux deployment targets

Pre-requisites

  • There are specific requirements when running on Windows.
  • HTTP Challenge Listener must be available on Port 80.
  • When updating the Octopus Certificate Store, access to the Octopus Server from where the script template runs e.g. deployment target or worker is required.

Parameters

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

Certificate Domain

LE_SelfHosted_CertificateDomain =

Domain (TLD, CNAME, or Wildcard) to create a certificate for.

Contact Email Address

LE_SelfHosted_ContactEmailAddress = #{Octopus.Deployment.CreatedBy.EmailAddress}

The Email address used when requesting the SSL certificate. Default: #{Octopus.Deployment.CreatedBy.EmailAddress}.

PFX Password

LE_SelfHosted_PfxPass =

The password to use when converting to/from PFX.

Use Lets Encrypt Staging

LE_SelfHosted_Use_Staging = False

Should the Certificate be generated using the Lets Encrypt Staging infrastructure? Default: False.

Http Listener Timeout

LE_SelfHosted_HttpListenerTimeout = 120

Self-Hosted Http Listener Timeout in Seconds. Default: 120 seconds.

Update Octopus Certificate Store?

LE_Self_Hosted_UpdateOctopusCertificateStore = True

Should any generated certificate be updated in the Octopus Deploy Certificate Store Default: True.

Octopus Deploy API key

LE_SelfHosted_Octopus_APIKey =

An Octopus Deploy API key with access to change Certificates in the Certificate Store.

Note: Required if LE_Self_Hosted_UpdateOctopusCertificateStore is set to True.

Replace expiring certificate before N days

LE_SelfHosted_ReplaceIfExpiresInDays = 30

Replace the certificate if it expiries within N days. Default: 30 days.

Note: Required if LE_Self_Hosted_UpdateOctopusCertificateStore is set to True.

Install Certificate?

LE_SelfHosted_Install = False

Installs the certificate in the local store. Default: False.

PFX Export Filepath

LE_SelfHosted_ExportFilePath =

Exports the full certificate chain as PKCS#12 archive (.PFX used by Windows and IIS) e.g. C:\Temp\octopus.com.pfx

Script body

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

# TLS 1.2
Write-Host "Enabling TLS 1.2 for script execution"
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.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
}

Write-Host "Importing Posh-ACME"
Import-Module Posh-ACME

# Variables
$LE_SelfHosted_CertificateDomain = $OctopusParameters["LE_SelfHosted_CertificateDomain"]
$LE_SelfHosted_Contact = $OctopusParameters["LE_SelfHosted_ContactEmailAddress"]
$LE_SelfHosted_PfxPass = $OctopusParameters["LE_SelfHosted_PfxPass"]
$LE_SelfHosted_Use_Staging = $OctopusParameters["LE_SelfHosted_Use_Staging"]
$LE_SelfHosted_HttpListenerTimeout = $OctopusParameters["LE_SelfHosted_HttpListenerTimeout"]
$LE_Self_Hosted_UpdateOctopusCertificateStore = $OctopusParameters["LE_Self_Hosted_UpdateOctopusCertificateStore"]
$LE_SelfHosted_Octopus_APIKey = $OctopusParameters["LE_SelfHosted_Octopus_APIKey"]
$LE_SelfHosted_ReplaceIfExpiresInDays = $OctopusParameters["LE_SelfHosted_ReplaceIfExpiresInDays"]
$LE_SelfHosted_Install = $OctopusParameters["LE_SelfHosted_Install"]
$LE_SelfHosted_ExportFilePath = $OctopusParameters["LE_SelfHosted_ExportFilePath"]
$LE_SelfHosted_Export = -not [System.String]::IsNullOrWhiteSpace($LE_SelfHosted_ExportFilePath)
$LE_SelfHosted_TempFileLocation=[System.IO.Path]::GetTempFileName()

# Consts
$LE_SelfHosted_Certificate_Name = "Lets Encrypt - $LE_SelfHosted_CertificateDomain"

# Issuer used in a cert could be one of multiple, including ones no longer supported by Let's Encrypt
$LE_SelfHosted_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_SelfHosted_Issuers = @("Let's Encrypt Authority X3", "E1", "E2", "R3", "R4", "R5", "R6", "R10", "R11")

# Helper(s)
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
    }
}

function Clean-TempFiles {
	if(Test-Path -Path $LE_SelfHosted_TempFileLocation) {
		Write-Debug "Removing temporary file..."
		Remove-Item $LE_SelfHosted_TempFileLocation -Force
	}
}

function Exit-Failure {
  	Clean-TempFiles
	Exit 1
}

function Exit-Success {
  	Clean-TempFiles
	Exit 0
}

# Functions
function Get-LetsEncryptCertificate {
    Write-Debug "Entering: Get-LetsEncryptCertificate"

    if ($LE_SelfHosted_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;
    }

    $le_account = Get-PAAccount
    if ($le_account) {
        Write-Host "Removing existing PA-Account..."
        Remove-PAAccount $le_account.Id -Force
    }
    
    Write-Host "Assigning new PA-Account..."
    $le_account = New-PAAccount -Contact $LE_SelfHosted_Contact -AcceptTOS -Force
    
    Write-Host "Requesting new order for $LE_SelfHosted_CertificateDomain..."
    $order = New-PAOrder -Domain $LE_SelfHosted_CertificateDomain -PfxPass $LE_SelfHosted_PfxPass -Force
    
    try {
    	Write-Host "Invoking Self-Hosted HttpChallengeListener with timeout of $LE_SelfHosted_HttpListenerTimeout seconds..."
    	Invoke-HttpChallengeListener -Verbose -ListenerTimeout $LE_SelfHosted_HttpListenerTimeout
        	
        Write-Host "Getting validated certificate..."
        $pArgs = @{ManualNonInteractive=$True}
        $cert = New-PACertificate $LE_SelfHosted_CertificateDomain -PluginArgs $pArgs
        
        if ($LE_SelfHosted_Install -eq $True) {
        	if (-not $IsWindows -and 'Desktop' -ne $PSEdition) {
              Write-Host "Installing certificate currently only works on Windows"
          	}
            else {
              Write-Host "Installing certificate to local store..."
              $cert | Install-PACertificate
            }
    	}
        
        # Linux showed weird $null issues using the .PfxFullChain path
        if(Test-Path -Path $LE_SelfHosted_TempFileLocation) {
        	Write-Debug "Creating temp copy of certificate to: $LE_SelfHosted_TempFileLocation"
        	$bytes = [System.IO.File]::ReadAllBytes($cert.PfxFullChain)
            New-Item -Path $LE_SelfHosted_TempFileLocation -ItemType "file" -Force
            [System.IO.File]::WriteAllBytes($LE_SelfHosted_TempFileLocation, $bytes)
        }
        
        if($LE_SelfHosted_Export -eq $True) {
        	Write-Host "Exporting certificate to: $LE_SelfHosted_ExportFilePath"
        	$bytes = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)
            New-Item -Path $LE_SelfHosted_ExportFilePath -ItemType "file" -Force
            [System.IO.File]::WriteAllBytes($LE_SelfHosted_ExportFilePath, $bytes)
    	}

        return $cert
    }
    catch {
        Write-Host "Failed to Create Certificate. Error Message: $($_.Exception.Message). See Debug output for details."
        Write-Debug (Get-WebRequestErrorBody -RequestError $_)
        Exit-Failure
    }
}

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" = $LE_SelfHosted_Octopus_APIKey }
    $octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates?search=$LE_SelfHosted_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_SelfHosted_Issuers
        if ($LE_SelfHosted_Use_Staging -eq $True) {
            $possible_issuers = $LE_SelfHosted_Fake_Issuers
        }

        return $certificates_search | Where-Object {
            $_.SubjectCommonName -eq $LE_SelfHosted_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-Failure
    }
}

function Publish-OctopusCertificate {
    param (
        [string] $JsonBody
    )

    Write-Debug "Entering: Publish-OctopusCertificate"

    if (-not ($JsonBody)) {
        Write-Host "Existing Certificate Id and a replace Certificate are required."
        Exit-Failure
    }

    $octopus_uri = $OctopusParameters["Octopus.Web.ServerUri"]
    $octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
    $octopus_headers = @{ "X-Octopus-ApiKey" = $LE_SelfHosted_Octopus_APIKey }
    $octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates"
	Write-Verbose "Preparing to publish to: $octopus_certificates_uri"
    
    try {
        Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing
        Write-Host "Published $LE_SelfHosted_CertificateDomain certificate to the Octopus Deploy Certificate Store."
    }
    catch {
        Write-Host "Failed to publish $LE_SelfHosted_CertificateDomain certificate. Error: $($_.Exception.Message). See Debug output for details."
        Write-Debug (Get-WebRequestErrorBody -RequestError $_)
        Exit-Failure
    }
}

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-Failure
    }

    $octopus_uri = $OctopusParameters["Octopus.Web.ServerUri"]
    $octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
    $octopus_headers = @{ "X-Octopus-ApiKey" = $LE_SelfHosted_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_SelfHosted_CertificateDomain certificate in the Octopus Deploy Certificate Store."
    }
    catch {
        Write-Error "Failed to replace $LE_SelfHosted_CertificateDomain certificate. Error: $($_.Exception.Message). See Debug output for details."
        Write-Debug (Get-WebRequestErrorBody -RequestError $_)
        Exit-Failure
    }
}

function Get-NewCertificatePFXAsJson {
    param (
        $Certificate
    )

    Write-Debug "Entering: Get-NewCertificatePFXAsJson"

    if (-not ($Certificate)) {
        Write-Host "Certificate is required."
        Exit-Failure
    }

    [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)
    $certificate_base64 = [convert]::ToBase64String($certificate_buffer)

    $certificate_body = @{
        Name = "$LE_SelfHosted_CertificateDomain";
        Notes            = "";
        CertificateData  = @{
            HasValue = $true;
            NewValue = $certificate_base64;
        };
        Password         = @{
            HasValue = $true;
            NewValue = $LE_SelfHosted_PfxPass;
        };
    }

    return $certificate_body | ConvertTo-Json
}

function Get-ReplaceCertificatePFXAsJson {
    param (
        $Certificate
    )

    Write-Debug "Entering: Get-ReplaceCertificatePFXAsJson"

    if (-not ($Certificate)) {
        Write-Host "Certificate is required."
        Exit-Failure
    }

    [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)
    $certificate_base64 = [convert]::ToBase64String($certificate_buffer)

    $certificate_body = @{
        CertificateData = $certificate_base64;
        Password        = $LE_SelfHosted_PfxPass;
    }

    return $certificate_body | ConvertTo-Json
}

# Main Execution starts here

Write-Debug "Running MAIN function..."

if ($LE_Self_Hosted_UpdateOctopusCertificateStore -eq $True) {
  Write-Host "Checking for existing Lets Encrypt Certificates in the Octopus Deploy Certificates Store..."
  $certificates = Get-OctopusCertificates

  # Check for PFX & PEM
  if ($certificates) {

      # Handle 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_SelfHosted_CertificateDomain."
      Write-Host "Checking to see if any expire within $LE_SelfHosted_ReplaceIfExpiresInDays days."

      # Check Expiry Dates
      $expiring_certificates = $certificates | Where-Object { [DateTime]$_.NotAfter -lt (Get-Date).AddDays($LE_SelfHosted_ReplaceIfExpiresInDays) }

      if ($expiring_certificates) {
          Write-Host "Found certificates that expire with $LE_SelfHosted_ReplaceIfExpiresInDays days. Requesting new certificates for $LE_SelfHosted_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..."
      }

	Write-Host "Completed running..."
    Exit-Success
  }
}

Write-Host "Requesting New Certificate for $LE_SelfHosted_CertificateDomain from Lets Encrypt"

$le_certificate = Get-LetsEncryptCertificate

if($LE_Self_Hosted_UpdateOctopusCertificateStore -eq $True) {
  Write-Host "Publishing new LetsEncrypt - $LE_SelfHosted_CertificateDomain (PFX) to Octopus Certificate Store"
  $certificate_as_json = Get-NewCertificatePFXAsJson -Certificate $le_certificate
  Publish-OctopusCertificate -JsonBody $certificate_as_json
} 
else {
  Write-Host "Certificate generated..."
  $le_certificate | fl
}

Write-Host "Completed running..."
Exit-Success

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": "e3614dd6-3a78-4220-97f0-b0e44415e58c",
  "Name": "Lets Encrypt - Self-Hosted HTTP Challenge",
  "Description": "Request (or renew) an X.509 SSL Certificate from the [Let's Encrypt Certificate Authority](https://letsencrypt.org/) using the Self-hosted HTTP Challenge Listener provided by the [Posh-ACME](https://github.com/rmbolger/Posh-ACME/) PowerShell Module.\n\n---\n#### Please Note\n\nIt's generally a better idea to use one of the Posh-ACME [DNS providers](https://github.com/rmbolger/Posh-ACME/wiki/List-of-Supported-DNS-Providers) for Let's Encrypt.\n\nThere are a number of Octopus Step templates in the [Community Library](https://library.octopus.com/listing/letsencrypt) that support DNS providers.\n\n---\n\n#### Features\n\n- ACME v2 protocol support which allows generating wildcard certificates (*.example.com).\n- [Self-hosted HTTP Challenge](https://github.com/rmbolger/Posh-ACME/wiki/How-To-Self-Host-HTTP-Challenges) Challenge for TLD, CNAME, and Wildcard domains. \n- _Optionally_ Publishes/Updates SSL Certificates in the [Octopus Deploy Certificate Store](https://octopus.com/docs/deployment-examples/certificates).\n- _Optionally_ import SSL Certificate into the local machine store. \n- _Optionally_ Export PFX (PKCS#12) SSL Certificate to a supplied file path.\n- Verified to work on Windows and Linux deployment targets\n\n#### Pre-requisites\n\n- There are specific requirements when [running on Windows](https://github.com/rmbolger/Posh-ACME/wiki/How-To-Self-Host-HTTP-Challenges#windows-only-prerequisites).\n- HTTP Challenge Listener must be available on Port 80.\n- When updating the Octopus Certificate Store, access to the Octopus Server from where the script template runs e.g. deployment target or worker is required.",
  "Version": 11,
  "ExportedAt": "2024-08-01T10:57:00.608Z",
  "ActionType": "Octopus.Script",
  "Author": "harrisonmeister",
  "Packages": [],
  "Parameters": [
    {
      "Id": "3d7e44e3-8a29-4458-b3ba-c09817566492",
      "Name": "LE_SelfHosted_CertificateDomain",
      "Label": "Certificate Domain",
      "HelpText": "Domain (TLD, CNAME, or Wildcard) to create a certificate for.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "7f882a93-511d-4c8c-a946-832d69739773",
      "Name": "LE_SelfHosted_ContactEmailAddress",
      "Label": "Contact Email Address",
      "HelpText": "The Email address used when requesting the SSL certificate. _Default: `#{Octopus.Deployment.CreatedBy.EmailAddress}`_.",
      "DefaultValue": "#{Octopus.Deployment.CreatedBy.EmailAddress}",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "c91935f5-64cb-48c3-940b-981fcbfb942a",
      "Name": "LE_SelfHosted_PfxPass",
      "Label": "PFX Password",
      "HelpText": "The password to use when converting to/from PFX.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "dd75b10a-17ca-4859-ae8d-adf0de74dbce",
      "Name": "LE_SelfHosted_Use_Staging",
      "Label": "Use Lets Encrypt Staging",
      "HelpText": "Should the Certificate be generated using the Lets Encrypt Staging infrastructure? _Default: `False`_.",
      "DefaultValue": "False",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "9a5d53f9-c5e5-4c83-9769-43b987ba04b0",
      "Name": "LE_SelfHosted_HttpListenerTimeout",
      "Label": "Http Listener Timeout",
      "HelpText": "Self-Hosted Http Listener Timeout in Seconds. _Default: 120 seconds_.",
      "DefaultValue": "120",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "7d8c49b8-684e-49d3-95aa-353c6e087843",
      "Name": "LE_Self_Hosted_UpdateOctopusCertificateStore",
      "Label": "Update Octopus Certificate Store?",
      "HelpText": "Should any generated certificate be updated in the [Octopus Deploy Certificate Store](https://octopus.com/docs/deployment-examples/certificates) _Default: `True`_.",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "83e2d3cf-66a6-47b4-bae8-e207a6918048",
      "Name": "LE_SelfHosted_Octopus_APIKey",
      "Label": "Octopus Deploy API key",
      "HelpText": "An Octopus Deploy API key with access to change Certificates in the Certificate Store. \n\n**Note:** Required if `LE_Self_Hosted_UpdateOctopusCertificateStore` is set to `True`.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "95ff51cc-2390-4b5d-89b0-bd62e83bb4f8",
      "Name": "LE_SelfHosted_ReplaceIfExpiresInDays",
      "Label": "Replace expiring certificate before N days",
      "HelpText": "Replace the certificate if it expiries within N days. _Default: 30 days_.\n\n**Note:** Required if `LE_Self_Hosted_UpdateOctopusCertificateStore` is set to `True`.",
      "DefaultValue": "30",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "d429561f-cf00-41f6-9956-e994f623696a",
      "Name": "LE_SelfHosted_Install",
      "Label": "Install Certificate?",
      "HelpText": "Installs the certificate in the local store. _Default: `False`_.",
      "DefaultValue": "False",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "f8abcf14-c9a1-4e15-87dc-95004f2216e6",
      "Name": "LE_SelfHosted_ExportFilePath",
      "Label": "PFX Export Filepath",
      "HelpText": "Exports the full certificate chain as PKCS#12 archive (.PFX used by Windows and IIS) e.g. C:\\Temp\\octopus.com.pfx",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "# TLS 1.2\nWrite-Host \"Enabling TLS 1.2 for script execution\"\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.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\nWrite-Host \"Importing Posh-ACME\"\nImport-Module Posh-ACME\n\n# Variables\n$LE_SelfHosted_CertificateDomain = $OctopusParameters[\"LE_SelfHosted_CertificateDomain\"]\n$LE_SelfHosted_Contact = $OctopusParameters[\"LE_SelfHosted_ContactEmailAddress\"]\n$LE_SelfHosted_PfxPass = $OctopusParameters[\"LE_SelfHosted_PfxPass\"]\n$LE_SelfHosted_Use_Staging = $OctopusParameters[\"LE_SelfHosted_Use_Staging\"]\n$LE_SelfHosted_HttpListenerTimeout = $OctopusParameters[\"LE_SelfHosted_HttpListenerTimeout\"]\n$LE_Self_Hosted_UpdateOctopusCertificateStore = $OctopusParameters[\"LE_Self_Hosted_UpdateOctopusCertificateStore\"]\n$LE_SelfHosted_Octopus_APIKey = $OctopusParameters[\"LE_SelfHosted_Octopus_APIKey\"]\n$LE_SelfHosted_ReplaceIfExpiresInDays = $OctopusParameters[\"LE_SelfHosted_ReplaceIfExpiresInDays\"]\n$LE_SelfHosted_Install = $OctopusParameters[\"LE_SelfHosted_Install\"]\n$LE_SelfHosted_ExportFilePath = $OctopusParameters[\"LE_SelfHosted_ExportFilePath\"]\n$LE_SelfHosted_Export = -not [System.String]::IsNullOrWhiteSpace($LE_SelfHosted_ExportFilePath)\n$LE_SelfHosted_TempFileLocation=[System.IO.Path]::GetTempFileName()\n\n# Consts\n$LE_SelfHosted_Certificate_Name = \"Lets Encrypt - $LE_SelfHosted_CertificateDomain\"\n\n# Issuer used in a cert could be one of multiple, including ones no longer supported by Let's Encrypt\n$LE_SelfHosted_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_SelfHosted_Issuers = @(\"Let's Encrypt Authority X3\", \"E1\", \"E2\", \"R3\", \"R4\", \"R5\", \"R6\", \"R10\", \"R11\")\n\n# Helper(s)\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            return $response | ConvertFrom-Json\n        }\n    }\n    else {\n        return $RequestError.ErrorDetails.Message\n    }\n}\n\nfunction Clean-TempFiles {\n\tif(Test-Path -Path $LE_SelfHosted_TempFileLocation) {\n\t\tWrite-Debug \"Removing temporary file...\"\n\t\tRemove-Item $LE_SelfHosted_TempFileLocation -Force\n\t}\n}\n\nfunction Exit-Failure {\n  \tClean-TempFiles\n\tExit 1\n}\n\nfunction Exit-Success {\n  \tClean-TempFiles\n\tExit 0\n}\n\n# Functions\nfunction Get-LetsEncryptCertificate {\n    Write-Debug \"Entering: Get-LetsEncryptCertificate\"\n\n    if ($LE_SelfHosted_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    $le_account = Get-PAAccount\n    if ($le_account) {\n        Write-Host \"Removing existing PA-Account...\"\n        Remove-PAAccount $le_account.Id -Force\n    }\n    \n    Write-Host \"Assigning new PA-Account...\"\n    $le_account = New-PAAccount -Contact $LE_SelfHosted_Contact -AcceptTOS -Force\n    \n    Write-Host \"Requesting new order for $LE_SelfHosted_CertificateDomain...\"\n    $order = New-PAOrder -Domain $LE_SelfHosted_CertificateDomain -PfxPass $LE_SelfHosted_PfxPass -Force\n    \n    try {\n    \tWrite-Host \"Invoking Self-Hosted HttpChallengeListener with timeout of $LE_SelfHosted_HttpListenerTimeout seconds...\"\n    \tInvoke-HttpChallengeListener -Verbose -ListenerTimeout $LE_SelfHosted_HttpListenerTimeout\n        \t\n        Write-Host \"Getting validated certificate...\"\n        $pArgs = @{ManualNonInteractive=$True}\n        $cert = New-PACertificate $LE_SelfHosted_CertificateDomain -PluginArgs $pArgs\n        \n        if ($LE_SelfHosted_Install -eq $True) {\n        \tif (-not $IsWindows -and 'Desktop' -ne $PSEdition) {\n              Write-Host \"Installing certificate currently only works on Windows\"\n          \t}\n            else {\n              Write-Host \"Installing certificate to local store...\"\n              $cert | Install-PACertificate\n            }\n    \t}\n        \n        # Linux showed weird $null issues using the .PfxFullChain path\n        if(Test-Path -Path $LE_SelfHosted_TempFileLocation) {\n        \tWrite-Debug \"Creating temp copy of certificate to: $LE_SelfHosted_TempFileLocation\"\n        \t$bytes = [System.IO.File]::ReadAllBytes($cert.PfxFullChain)\n            New-Item -Path $LE_SelfHosted_TempFileLocation -ItemType \"file\" -Force\n            [System.IO.File]::WriteAllBytes($LE_SelfHosted_TempFileLocation, $bytes)\n        }\n        \n        if($LE_SelfHosted_Export -eq $True) {\n        \tWrite-Host \"Exporting certificate to: $LE_SelfHosted_ExportFilePath\"\n        \t$bytes = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)\n            New-Item -Path $LE_SelfHosted_ExportFilePath -ItemType \"file\" -Force\n            [System.IO.File]::WriteAllBytes($LE_SelfHosted_ExportFilePath, $bytes)\n    \t}\n\n        return $cert\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-Failure\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\" = $LE_SelfHosted_Octopus_APIKey }\n    $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates?search=$LE_SelfHosted_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_SelfHosted_Issuers\n        if ($LE_SelfHosted_Use_Staging -eq $True) {\n            $possible_issuers = $LE_SelfHosted_Fake_Issuers\n        }\n\n        return $certificates_search | Where-Object {\n            $_.SubjectCommonName -eq $LE_SelfHosted_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-Failure\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 Id and a replace Certificate are required.\"\n        Exit-Failure\n    }\n\n    $octopus_uri = $OctopusParameters[\"Octopus.Web.ServerUri\"]\n    $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n    $octopus_headers = @{ \"X-Octopus-ApiKey\" = $LE_SelfHosted_Octopus_APIKey }\n    $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates\"\n\tWrite-Verbose \"Preparing to publish to: $octopus_certificates_uri\"\n    \n    try {\n        Invoke-WebRequest -Uri $octopus_certificates_uri -Method Post -Headers $octopus_headers -Body $JsonBody -UseBasicParsing\n        Write-Host \"Published $LE_SelfHosted_CertificateDomain certificate to the Octopus Deploy Certificate Store.\"\n    }\n    catch {\n        Write-Host \"Failed to publish $LE_SelfHosted_CertificateDomain certificate. Error: $($_.Exception.Message). See Debug output for details.\"\n        Write-Debug (Get-WebRequestErrorBody -RequestError $_)\n        Exit-Failure\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-Failure\n    }\n\n    $octopus_uri = $OctopusParameters[\"Octopus.Web.ServerUri\"]\n    $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n    $octopus_headers = @{ \"X-Octopus-ApiKey\" = $LE_SelfHosted_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_SelfHosted_CertificateDomain certificate in the Octopus Deploy Certificate Store.\"\n    }\n    catch {\n        Write-Error \"Failed to replace $LE_SelfHosted_CertificateDomain certificate. Error: $($_.Exception.Message). See Debug output for details.\"\n        Write-Debug (Get-WebRequestErrorBody -RequestError $_)\n        Exit-Failure\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-Failure\n    }\n\n    [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)\n    $certificate_base64 = [convert]::ToBase64String($certificate_buffer)\n\n    $certificate_body = @{\n        Name = \"$LE_SelfHosted_CertificateDomain\";\n        Notes            = \"\";\n        CertificateData  = @{\n            HasValue = $true;\n            NewValue = $certificate_base64;\n        };\n        Password         = @{\n            HasValue = $true;\n            NewValue = $LE_SelfHosted_PfxPass;\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-Failure\n    }\n\n    [Byte[]]$certificate_buffer = [System.IO.File]::ReadAllBytes($LE_SelfHosted_TempFileLocation)\n    $certificate_base64 = [convert]::ToBase64String($certificate_buffer)\n\n    $certificate_body = @{\n        CertificateData = $certificate_base64;\n        Password        = $LE_SelfHosted_PfxPass;\n    }\n\n    return $certificate_body | ConvertTo-Json\n}\n\n# Main Execution starts here\n\nWrite-Debug \"Running MAIN function...\"\n\nif ($LE_Self_Hosted_UpdateOctopusCertificateStore -eq $True) {\n  Write-Host \"Checking for existing Lets Encrypt Certificates in the Octopus Deploy Certificates Store...\"\n  $certificates = Get-OctopusCertificates\n\n  # Check for PFX & PEM\n  if ($certificates) {\n\n      # Handle 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_SelfHosted_CertificateDomain.\"\n      Write-Host \"Checking to see if any expire within $LE_SelfHosted_ReplaceIfExpiresInDays days.\"\n\n      # Check Expiry Dates\n      $expiring_certificates = $certificates | Where-Object { [DateTime]$_.NotAfter -lt (Get-Date).AddDays($LE_SelfHosted_ReplaceIfExpiresInDays) }\n\n      if ($expiring_certificates) {\n          Write-Host \"Found certificates that expire with $LE_SelfHosted_ReplaceIfExpiresInDays days. Requesting new certificates for $LE_SelfHosted_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\tWrite-Host \"Completed running...\"\n    Exit-Success\n  }\n}\n\nWrite-Host \"Requesting New Certificate for $LE_SelfHosted_CertificateDomain from Lets Encrypt\"\n\n$le_certificate = Get-LetsEncryptCertificate\n\nif($LE_Self_Hosted_UpdateOctopusCertificateStore -eq $True) {\n  Write-Host \"Publishing new LetsEncrypt - $LE_SelfHosted_CertificateDomain (PFX) to Octopus Certificate Store\"\n  $certificate_as_json = Get-NewCertificatePFXAsJson -Certificate $le_certificate\n  Publish-OctopusCertificate -JsonBody $certificate_as_json\n} \nelse {\n  Write-Host \"Certificate generated...\"\n  $le_certificate | fl\n}\n\nWrite-Host \"Completed running...\"\nExit-Success"
  },
  "Category": "Lets Encrypt",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/letsencrypt-selfhosted-http.json",
  "Website": "/step-templates/e3614dd6-3a78-4220-97f0-b0e44415e58c",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Thursday, August 1, 2024