Octopus - Check Certficate Expiry

Octopus.Script exported 2021-08-23 by benjimac93 belongs to ‘Octopus’ category.

Checks for certificates stored in the Octopus Certificate library which are due to expire within N days.

Output variable usage

An Output variable named ExpiringCertificateJson is created with a JSON array of all of the matching expiring certificates with the following properties:

  • Certificate Name
  • Certificate Thumbprint
  • Certificate SubjectCommonName
  • Certificate Issuer
  • Certificate NotAfter

The Output variable can then be used in a subsequent step. Consider a step named Check Expiring Certs which uses this step template.

Adding the following PowerShell script to a subsequent step would iterate over the expiring certificates and highlight them in the Octopus Deployment log:


Write-Highlight "Expiring Certificates:"
#{each cert in Octopus.Action[Check Expiring Certs].Output.ExpiringCertificateJson}
Write-Highlight "- #{cert.Name} (#{cert.Thumbprint}) expires #{cert.NotAfter}"
#{/each}

Note: If the Output variable is empty, this indicates that there were no matching certificates that meet the specified expiry window.

Pre-requisites

  • Access to the Octopus Server from where the script template runs (e.g. deployment target or worker) is required.
  • An Octopus Server running 2019.1 or greater, as Space support is required.

Parameters

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

Octopus Url

Certificate.Expiry.Check.OctopusServerUrl = #{if Octopus.Web.ServerUri}#{Octopus.Web.ServerUri}#{else}#{Octopus.Web.BaseUrl}#{/if}

Provide the URL of your Octopus Server. The default is #{if Octopus.Web.ServerUri}#{Octopus.Web.ServerUri}#{else}#{Octopus.Web.BaseUrl}#{/if}. Cloud instances should use Octopus.Web.ServerUri. See System Variables - Server for more info.

Octopus API Key

Certificate.Expiry.Check.ApiKey =

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

Expiring within N days

Certificate.Expiry.Check.Days = 30

Enter the number of days to check within the certificates expire

Certificate Domain to check

Certificate.Expiry.Check.CertificateDomain =

Optional certificate domain to search for. If this parameter is blank or empty, all certificates will be checked for expiry.

Script body

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

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

function Get-OctopusCertificates {
    Write-Debug "Entering: Get-OctopusCertificates"

    $octopus_uri = $OctopusParameters["Certificate.Expiry.Check.OctopusServerUrl"].Trim('/')
    $octopus_space_id = $OctopusParameters["Octopus.Space.Id"]
    $octopus_headers = @{ "X-Octopus-ApiKey" = $OctopusParameters["Certificate.Expiry.Check.ApiKey"] }
    $octopus_certificates_uri = "$octopus_uri/api/$octopus_space_id/certificates?search=$($OctopusParameters["Certificate.Expiry.Check.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

        return $certificates_search | Where-Object {
            $null -eq $_.ReplacedBy -and
            $null -eq $_.Archived
        }
    }
    catch {
        Write-Host "Could not retrieve certificates from Octopus Deploy. Error: $($_.Exception.Message)."
        exit 1
    }
}

Write-Host "Checking for existing certificates in the Octopus Deploy Certificates Store."
$certificates = Get-OctopusCertificates

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 matching domain: $($OctopusParameters["Certificate.Expiry.Check.CertificateDomain"])."
    Write-Host "Checking to see if any expire within $($OctopusParameters["Certificate.Expiry.Check.Days"]) days."

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

    if ($expiring_certificates) {
        Write-Host "Found certificates that expire with $($OctopusParameters["Certificate.Expiry.Check.Days"]) days."
        
        $expiring_certs_json = $expiring_certificates | select Name, Thumbprint, SubjectCommonName, Issuer, NotAfter | ConvertTo-Json
        Set-OctopusVariable -name "ExpiringCertificateJson" -value $expiring_certs_json

    }
    else {
    	Set-OctopusVariable -name "ExpiringCertificateJson" -value ""
        Write-Host "Nothing to do here..."
    }

    exit 0
}

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": "8ca02a74-b2a1-482e-a2b3-5493016513ba",
  "Name": "Octopus - Check Certficate Expiry",
  "Description": "Checks for certificates stored in the [Octopus Certificate library](https://octopus.com/docs/deployment-examples/certificates) which are due to expire within N days.\n\n#### Output variable usage\n\nAn [Output variable](https://octopus.com/docs/projects/variables/output-variables) named `ExpiringCertificateJson` is created with a JSON array of all of the matching expiring certificates with the following properties: \n- Certificate Name\n- Certificate Thumbprint\n- Certificate SubjectCommonName\n- Certificate Issuer\n- Certificate NotAfter \n\n---\nThe Output variable can then be used in a subsequent step. Consider a step named `Check Expiring Certs` which uses this step template. \n\nAdding the following PowerShell script to a subsequent step would iterate over the expiring certificates and highlight them in the Octopus Deployment log:\n\n```powershell\n\nWrite-Highlight \"Expiring Certificates:\"\n#{each cert in Octopus.Action[Check Expiring Certs].Output.ExpiringCertificateJson}\nWrite-Highlight \"- #{cert.Name} (#{cert.Thumbprint}) expires #{cert.NotAfter}\"\n#{/each}\n```\n**Note:** If the Output variable is empty, this indicates that there were no matching certificates that meet the specified expiry window.\n\n#### Pre-requisites\n- Access to the Octopus Server from where the script template runs (e.g. deployment target or worker) is required.\n- An Octopus Server running **2019.1** or greater, as Space support is required.",
  "Version": 2,
  "ExportedAt": "2021-08-23T12:40:10.975Z",
  "ActionType": "Octopus.Script",
  "Author": "benjimac93",
  "Packages": [],
  "Parameters": [
    {
      "Id": "5fd60708-3183-4bfa-b042-a7ce6f8cb1a8",
      "Name": "Certificate.Expiry.Check.OctopusServerUrl",
      "Label": "Octopus Url",
      "HelpText": "Provide the URL of your Octopus Server. The default is `#{if Octopus.Web.ServerUri}#{Octopus.Web.ServerUri}#{else}#{Octopus.Web.BaseUrl}#{/if}`. Cloud instances should use `Octopus.Web.ServerUri`. See [System Variables - Server](https://octopus.com/docs/projects/variables/system-variables#Systemvariables-Server) for more info.",
      "DefaultValue": "#{if Octopus.Web.ServerUri}#{Octopus.Web.ServerUri}#{else}#{Octopus.Web.BaseUrl}#{/if}",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "33fe56db-a089-4979-b103-a502b6e442ba",
      "Name": "Certificate.Expiry.Check.ApiKey",
      "Label": "Octopus API Key",
      "HelpText": "An Octopus Deploy API key with access to change Certificates in the Certificate Store. ",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "00fc5429-bec2-44bc-bdb8-72c578d08d48",
      "Name": "Certificate.Expiry.Check.Days",
      "Label": "Expiring within N days",
      "HelpText": "Enter the number of days to check within the certificates expire",
      "DefaultValue": "30",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "a20adf80-285c-4690-aa1e-39b3926dd310",
      "Name": "Certificate.Expiry.Check.CertificateDomain",
      "Label": "Certificate Domain to check",
      "HelpText": "*Optional* certificate domain to search for. If this parameter is blank or empty, all certificates will be checked for expiry.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptBody": "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n\nfunction Get-OctopusCertificates {\n    Write-Debug \"Entering: Get-OctopusCertificates\"\n\n    $octopus_uri = $OctopusParameters[\"Certificate.Expiry.Check.OctopusServerUrl\"].Trim('/')\n    $octopus_space_id = $OctopusParameters[\"Octopus.Space.Id\"]\n    $octopus_headers = @{ \"X-Octopus-ApiKey\" = $OctopusParameters[\"Certificate.Expiry.Check.ApiKey\"] }\n    $octopus_certificates_uri = \"$octopus_uri/api/$octopus_space_id/certificates?search=$($OctopusParameters[\"Certificate.Expiry.Check.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        return $certificates_search | Where-Object {\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).\"\n        exit 1\n    }\n}\n\nWrite-Host \"Checking for existing certificates in the Octopus Deploy Certificates Store.\"\n$certificates = Get-OctopusCertificates\n\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 matching domain: $($OctopusParameters[\"Certificate.Expiry.Check.CertificateDomain\"]).\"\n    Write-Host \"Checking to see if any expire within $($OctopusParameters[\"Certificate.Expiry.Check.Days\"]) days.\"\n\n    # Check Expiry Dates\n    $expiring_certificates = $certificates | Where-Object { [DateTime]$_.NotAfter -lt (Get-Date).AddDays($OctopusParameters[\"Certificate.Expiry.Check.Days\"]) }\n\n    if ($expiring_certificates) {\n        Write-Host \"Found certificates that expire with $($OctopusParameters[\"Certificate.Expiry.Check.Days\"]) days.\"\n        \n        $expiring_certs_json = $expiring_certificates | select Name, Thumbprint, SubjectCommonName, Issuer, NotAfter | ConvertTo-Json\n        Set-OctopusVariable -name \"ExpiringCertificateJson\" -value $expiring_certs_json\n\n    }\n    else {\n    \tSet-OctopusVariable -name \"ExpiringCertificateJson\" -value \"\"\n        Write-Host \"Nothing to do here...\"\n    }\n\n    exit 0\n}\n"
  },
  "Category": "Octopus",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/octopus-certificate-expiry-check.json",
  "Website": "/step-templates/8ca02a74-b2a1-482e-a2b3-5493016513ba",
  "Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1QTFRFT6Tl////L5Pg8vj9Y67omsvwPJrisdfzfbzs5fL7y+T32Ov5isLucLXqvt31CJPHWwAABMJJREFUeNrs3deW4jAMAFDF3U75/89dlp0ZhiU4blJEjvQ8hYubLJsA00UCBCIQgQhEIAIRiEAEIhCBCEQgAhGIQAQiEIEIhD8kJm+t+QprfdKfB9HbYpx6CWfspj8HMi+gMgHL/AmQA8W3JTKH+ALFvzCeL0RbpyoCPE9IJeNOSQwh5Z3qd6yRGWQ2qi2cZQWxqj1WzQYSjeoJmJlAklOd4VlArOqPhQEkqBERToeMcfRJBkC0Uep8CfBpjz4JsHJ0zF3dkEWNje0kiB/sUC6eApndaIiCMyAa1PiwJ0AWhRGJHJJQHG2dC7h1rNbO1QOxSA7lNCkkKrQIpJCAB1GREILYIC1NAiwbpKFJgGWDNExcwGstfExcZBCHC6nOglshHtmhViLIig1RNBCN7qjtW8C0Z1UvJcC1Z9XmwMBzzvobmgAyEzgq91dtEEsBsQSQQAFZCSBAATEEEApHZbrVBIkkEIUPSVeB+KtALA0kXQUSrwKZBCIQBnk8Y4i5CsReBeKvkqLM+BCSDWJlrZFvGk9SRTHshkgjZCGAaArIxm3H3grhVzFlW2msfl1ca79UJ1bofYvsDHHlNdTZnlh5MghuPd5NdBDUNZHyCkfktIh03XzALGRPlBDPac7qgWjHZzWcmF5zmmkhidMQ6boKiDXcDTUEaylZqCGJ0Vjvu/fLJtHqhSANEvqb2OYqkOUqEHuVMbJcZdZCGiPhKhC4yjqiIjEE7XThMp8fAWII3mY3kUIQD+AMKQTzPiBhgQ63HlT/KSvgtoi0dq5mCPah1UIE0eh3sT0NhOByvKeAkFzi8PgQomumFhsyOxpIzZN4gLOj5plVwNpR0b2AuePWKBEHQu24pSsJA+LVCeHHQxZ1SiyDIdqok8IOhSSnTottHEQTdyt4ettAj4KkzA4dMikk2Dht2S5ptm1vswnPDxn0YyDZ5oDM3iToo2T5voWaYe+Q+vdjH80QyAzZhCgcDtLMI1Tmtz9w++XHgziHQHJJu/OZ3bs9Xn8gQ72NcP3dKqEfkp10F51xhoIi2I91R+LurXV/5q7pH+wx061CzO16oSQleMyr8fXvwMA0Pro8432DPD/ySx8XrHfSuDAM8n6UhnjQabaiXf5Bq/lREHvEeNtn1rJ08+C/uXkQZHeguxAPC3UvtcJYUogLzZX5hhZZvS6onG5lxXtzWGaygwb79vT/IXhdlNibwlKYOR6T8xjI7W8n+xV7T+GH4tMzWwR+lZhRkJYSsC0thpmCYqyngOz3rN2FLBZ2wZflBCggUHF0Vnp88JKienzIXLSEZCZqU7IKr/gQW9yx3pzV7Y9kvWZWTRRIqDmTtRUnU7b2lLcTYmoqHqnmiO1poER0SPkAeZMAZxaJx0Y3TCdAclsIqDz03ALcyxfTCZBsthoGXWmigGyVhWPLFJJfuuKQWycoEFdXbH4dJJoJxNR1eD/kshz6yn48cF8yW8sFoitflB1w6Q8n+/15Za7oA17/pYNmYgP5fmWm8L1NOHPWgK8kuFew1/JXtOA0yJCv7ah7X8ObUuT5kObU30+fDZm8+zqP+HTIpK0xQ796b5Kv2hSIQAQiEIEIRCACEYhABCIQgQhEIAIRiEAEIpBf8UeAAQAEjtYmlDTcCgAAAABJRU5ErkJggg==",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Monday, August 23, 2021