Leverage HashiCorp Vault as a trusted certificate authority (CA) to issue short-lived code signing certificates to a GitHub Actions workflow.
Code signing is an essential element of software supply chain security, enabling users of your code to verify that the code they are running is actually the code you released. This helps defend against supply chain attacks such as dependency confusion attacks by supporting end-users’ ability to verify code authorship and enforce code-integrity controls.
At a high level, code signing workflows depend on four components:
This blog post focuses on leveraging HashiCorp Vault as a trusted CA to issue short-lived code signing certificates to a GitHub Actions workflow that signs a PowerShell script using Microsoft Authenticode.
The diagram below illustrates the workflow of this solution:
This workflow uses a two-tier public key infrastructure (PKI). We’ll use OpenSSL to operate the root CA and Vault to operate the code signing issuing CA.
You can see an entire sample code repository of this post’s solution in the code signing with Vault GitHub repository.
Once you have a copy of the sample code repository linked above, navigate to the root-ca
directory, then review and execute the generate
script (./generate
).
This script will generate an Elliptic Curve P-521 key pair and issue a self-signed root certificate. You’ll find the corresponding certificate in root.crt
, and the EC parameters and private key will be in root.key
.
The sample code in the repository also includes a HashiCorp Terraform module that provisions the required resources in Vault. Once you have a Vault cluster up and running, take the following three steps (Note: the HashiCorp Cloud Platform, also called HCP, makes this step much easier):
terraform
directory.pki_codesign_cert
to null
for the time being (more on that later).terraform apply
, review the plan, and deploy the changes to your Vault cluster.At this point, you’ll have these items in your Vault cluster:
Since the root CA is offline under OpenSSL, the next step is to have the root CA issue a certificate for Vault’s code signing CA.
Retrieve the Vault CA’s certificate signing request from the Terraform outputs and paste it into a file under the root-ca
directory. Name that file codesigning-ca.csr
. You can inspect the contents of the CSR with OpenSSL:
openssl req -in codesign-ca.csr -noout -text
If you’re satisfied with the parameters of the CSR, run the sign
script (./sign
) to have the root CA issue the certificate for Vault's CA. The certificate will be stored in codesign-ca.crt
.
Next, import Vault’s CA certificate by modifying your Terraform variables file to include both the Vault CA certificate and the root CA certificate:
pki_codesign_cert = <<EOF
-----BEGIN CERTIFICATE-----
Vault CA cert here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Root CA cert here
-----END CERTIFICATE-----
EOF
The repository for this post includes a sample GitHub workflow you can use to test this code signing pipeline concept.
Note that this is not a production-ready workflow. At the very least, you don’t want to download the Vault CLI every time without further security checks.
Once the hello-world.ps1
script is signed by your pipeline, you can check its Authenticode signature by running:
Get-AuthenticodeSignature -FilePath .\hello-world.ps1 | Format-List
Be sure that your computer trusts the root CA used for this exercise or signature verification will fail. If you’re not using a discardable environment, remember to remove the root CA certificate from the trust store when you’re done with signature verification.
Code signing traditionally relies on certificates issued by CAs, such as DigiCert and GlobalSign, that are trusted by the major software vendors. These CAs must verify the identity of the individual or organization requesting the certificate, a process that is often manual, lengthy, and expensive.
If you are distributing software broadly, it makes sense to go through that process: you’ll be issued a certificate that is automatically trusted by all your users by virtue of the CA being part of the major vendors’ trusted CA programs.
But what if you’re looking to secure internal distribution of software, e.g. ensuring that a line-of-business application was built by an approved system and not tampered with since? In that case, ask yourself the following questions:
The solution outlined in this post gives your business important benefits when internally distributing software:
Learn more about how Vault helps organizations run secure and efficient PKI from this HashiConf talk on automating PKI with Vault, and find out how to build your own certificate authority with Vault on HashiCorp Developer.
HashiCorp will be at AWS re:Inforce sharing expert talks, product demos, and news announcements.
New Security Lifecycle Management (SLM) offerings from HashiCorp Vault and Boundary help organizations protect, inspect, and connect their most sensitive data.
Protect, inspect, and connect your sensitive data with Security Lifecycle Management solutions from HashiCorp.