How to Import Certificate to AWS ACM via Octopus/Powershell

Hi Team,
I have been struggling with weird issue recently, I know its not related to Octopus functionality but I want to achieve this functionality via Octopus hence asking this question here.
I store the Certificate Private Key, Certificate Body and Certificate Chain in the Octopus variables manually. Now I want to import this into AWS ACM using AWS Cli. However whenever I run code down below at end of post, it errors out due to “-----BEGIN CERTIFICATE-----” and “-----END CERTIFICATE-----” these lines in the certificate. So to trim down the issue further I am only trying to save the Octopus variable with cert details into local file but its failing with this error -

ParserError: At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:1 char:17

February 2nd 2022 22:04:25

Error

  • $certBody = -----BEGIN CERTIFICATE-----

February 2nd 2022 22:04:25

Error

  • ~

February 2nd 2022 22:04:25

Error

Missing expression after unary operator ‘–’.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:1 char:17

February 2nd 2022 22:04:25

Error

  • $certBody = -----BEGIN CERTIFICATE-----

February 2nd 2022 22:04:25

Error

  • 
    

February 2nd 2022 22:04:25

Error

Unexpected token ‘-BEGIN’ in expression or statement.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:1 char:24

February 2nd 2022 22:04:25

Error

  • $certBody = -----BEGIN CERTIFICATE-----

February 2nd 2022 22:04:25

Error

  • 
    

February 2nd 2022 22:04:25

Error

Unexpected token ‘CERTIFICATE-----’ in expression or statement.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:12 char:3

February 2nd 2022 22:04:25

Error

  • 4+mOIcrKAcPgDx5kA5FMkwfxJUXrnqxxfjFAfxj2pn7RFIzvoCWM6ZxZNf9GgnOT

February 2nd 2022 22:04:25

Error

  • ~

February 2nd 2022 22:04:25

Error

You must provide a value expression following the ‘+’ operator.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:12 char:3

February 2nd 2022 22:04:25

Error

  • 4+mOIcrKAcPgDx5kA5FMkwfxJUXrnqxxfjFAfxj2pn7RFIzvoCWM6ZxZNf9GgnOT

February 2nd 2022 22:04:25

Error

  • 
    

February 2nd 2022 22:04:25

Error

Unexpected token ‘mOIcrKAcPgDx5kA5FMkwfxJUXrnqxxfjFAfxj2pn7RFIzvoCWM6ZxZNf9GgnOT’ in expression or statement.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:36 char:3

February 2nd 2022 22:04:25

Error

  • 2+KBdo0IVu4A3bPHRfliSJl7Exo118zifIgMCh5d6cETER6MHT2lgObHUzDKX4XD

February 2nd 2022 22:04:25

Error

  • ~

February 2nd 2022 22:04:25

Error

You must provide a value expression following the ‘+’ operator.

February 2nd 2022 22:04:25

Error

At E:\Octopus.Tentacle.v4\v4-octopus.deploy.internal.cba\Work\20220202110419-711063-1116\Script.ps1:36 char:3

February 2nd 2022 22:04:25

Error

  • 2+KBdo0IVu4A3bPHRfliSJl7Exo118zifIgMCh5d6cETER6MHT2lgObHUzDKX4XD

Below is my code in the AWS CLI step of Octopus -

$certBody = #{CertBody}

Set-Content -Path .\PrivateKey.key -Value $certBody

Where value of #{CertBody} is something like below (truncated actual value for demo purpose)

-----BEGIN CERTIFICATE-----
MIIHpTCCBY2gAwIBAgITUAADbxDFrPNPOXV8igAAAANvEDANBgkqhkiG9w0BAQsF
ADCBpDELMAkGA1UEBhMCQVUxGDAWBgNVBAgTD05ldyBTb3V0aCBXYWxlczEPMA
DX0eNWCltqdUAQqVdVCBeiSndMJGS+Gb5MDkOLIcaq1zjgtVcOXLGIa+o+B3nUoG
0VT0hK3sH2Gt4E2uhHWIt0Q360KYUTUfgMkg1eiDNr+TWcKWm3lU548=
-----END CERTIFICATE-----

Hi @harsh_tech

The main error you are getting in your script example is that the #{CertBody} is not contained within quotes:

$certBody = "#{CertBody}"

The complete example would be this:

$certBody = "#{CertBody}"

Set-Content -Path .\PrivateKey.key -Value $certBody

Another thing to be aware of is that by default a Single line text variable in Octopus will strip all new line characters and replace them with spaces. You can reconstruct the certificate body, but you’ll need to manually do that if you’re using a normal variable. It’d be worth considering the use of the built-in certificate store and using a Certificate variable, which has extended properties you can access which handle all of the newline / conversion for you.

Hope that helps!

1 Like

Thanks @mark.harrison I did not know I can use the Certificate Variable… Thanks for that info. Do you know if I can use Octopus API to update this Certificate Variable, because I want to automate updating this variable from powershell script using Octopus Apis.

Hi @harsh_tech

Thanks for your reply!

Yes, we have examples to both create a new certificate and modify an existing one by way of replacing an existing one. As far as I know, we don’t support updating individual properties of a certificate object itself, except maybe the name of it within Octopus.

You can see the examples here:

One thing to note about using the REST API in general, but also specific to your certificates query is that the API will never return sensitive data e.g. private key data or any password information. This is by design, and can’t be accessed using the API.

I hope that helps!

1 Like

Thanks heaps @mark.harrison .this is excellent. I will try this. It will make my life so much easy to work with Certificates.

Hi @harsh_tech

You’re very welcome!

Have a great rest of your day.

Best,

Hi @mark.harrison , I tried this Octopus.Client code here Replace existing certificate - Octopus Deploy

however I get null for $repository.Spaces
Not sure whether that’s because my Octopus setup or this property is deprecated now.
Also I can’t see a reference code to update the Certificate in particular project and environment. If you could help to provide the reference link for that, it would be very helpful

Hi @harsh_tech

You didn’t mention which version of the code you were using from the example you linked to, but based on your code snippet, I assumed it was the PowerShell (Octopus.Client) version.

Without additional information, it’s not possible to know the cause of the exact null value you are receiving.
I tested the script using Octopus.Client version 8.4.4.0 (which is not the latest), and tested this against an Octopus Server running 2021.3.

I’d recommend checking a few things:

  • The version of Octopus.Client supports the $client.ForSpace($space) method (I’m not sure the exact version it was added in)
  • The version of Octopus.Server supports spaces in general. They were added in 2019.1
  • The Space name exists in your Octopus instance.

That’s correct, this example will only replace a certificate in the Octopus Certificate store. This is a central place to store certificates. Therefore there isn’t any reference to projects and environments in the script.

If you are referencing a certificate in an Octopus project using a certificate variable, then when you update the certificate in the certificate store the value used at deployment time should be the updated (replaced) version. This is because the project certificate variable is a reference to a certificate, and not the actual certificate value in the variable, more like a pointer to the one in the Octopus cert store.

Hopefully, that makes sense, but if you’re intending to use a different type of variable then let me know some more details, and I can help further.

Best,

1 Like

Thanks @mark.harrison you are spot on, yes I was using quite old version of Octopus.Client dll. So I managed to get pass that hurdle, however I am getting below error for given code

           $space = $repository.Spaces.FindByName($spaceName)
            $repositoryForSpace = $client.ForSpace($space)

            # Fill in certificate details
            $pfxFilePath = $NewvalueFilePath 
            $pfxBase64 = [Convert]::ToBase64String((Get-Content -Path $pfxFilePath -AsByteStream)) 

            $pfxPassword = $Password

            # Check if Cert already exists 
            $currentCertificate = $repositoryForSpace.Certificates.FindAll() | Where-Object {($_.Name -eq $VarName) -and ($null -eq $_.Archived)} 

            # Check to see if multiple certificates were returned
            if ($currentCertificate -is [array])
            {
                # throw error
                throw "Multiple certificates returned!"
            }

            if($currentCertificate -eq $null) 
            {
                # Create certificate
                $certificateResource = New-Object -TypeName "Octopus.Client.Model.CertificateResource" -ArgumentList @($VarName, $pfxBase64, $pfxPassword) 
                $certificateResource = $repositoryForSpace.Certificates.Create($certificateResource);
            }
            else
            {
                #Replace existing Certificate
                $replacementCertificate = $repositoryForSpace.Certificates.Replace($currentCertificate, $pfxBase64, $pfxPassword);
            }

Exception calling “Create” with “1” argument(s): "There was a problem with your request.

  • Could not parse certificate data. Possible causes: 1) The certificate format is not supported. 2) The password is incorrect. 3) The file is corrupt. Error: Unable to parse certificate ‘www.my.dev1.commbiz.online.cba’
    (id: ): Unknown encryption algorithm: 1.2.840.113549.1.5.13

I am sure the certificate is correct at first place but do you think it could be happening due to Base64 encoding?

Hi @harsh_tech

I suspect that issue is caused by the library used internally by Octopus to create a certificate object. The library in question is called BouncyCastle

Generally speaking, it means the library can’t read the certificate file. You can see the supported file formats here:

I actually suspect it is a supported format, but rather the file was created with an unsupported version of OpenSSL. We’ve had a few reports of that specific error message when the certificate was created with OpenSSL 3.0.0+.

Usually creating the certificate in OpenSSL 1.1.1 fixes the problem. You could also import it into the Windows certificate store and export it using the Certificates snap-in.

I appreciate that it’s yet another step to go through, but unfortunately, we rely on the third-party library to provide support for certificate parsing, so are at the mercy of what it supports in this case.

We also have an open issue you can track here:

I hope that helps!

Thanks again @mark.harrison you saved my day. I installed openssl version 1.1.1 and it seems to have progressed further. I got further error but it seems be related to my permissions probably(I can create variables via API though) -

Exception calling “Create” with “1” argument(s): “You do not have permission to perform this action. Please contact your Octopus administrator. Missing permission: CertificateCreate”

Hi @harsh_tech

You are most welcome, I’m glad you are making steady progress :slight_smile:

That permission (CertificateCreate) will need to be granted to your user (or whichever user the API-Key is assigned to that you use in your scripts) in order to replace a certificate.

This permission is separate from being able to update variable values. I’d recommend speaking with whoever handles your security permissions in Octopus to see if you can have access granted.

I hope that helps!

Best,

1 Like

Thanks @mark.harrison.
@mark.harrison Do you know how can I scope this certificate to particular environment via PowerShell (Octopus.Client) version. I don’t see that in examples.

Hi @harsh_tech

We don’t have an example of this in our docs currently, but here is one I created in our associated GitHub repository to add an environment restriction:

The main difference between adding the environment restriction and replacing is the call you make on the Octopus Client (Replace vs Modify)

Hope that helps!

Best,

1 Like

Thank you so much @mark.harrison for writing up a quick example.

Hi @harsh_tech

You’re very welcome, hope that helped and that you have a lovely weekend!

Best,

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.