OPNsense(23.7) - bugfix ACME Plugin Upload to Hashicorp Vault

OPNsense(23.7) - bugfix ACME Plugin Upload to Hashicorp Vault

When trying to use the OPNsense ACME Client feature to upload Let's Encrypt certificates to Hashicorp Vault, it needed to be fixed.

The challenge started when the automation began to fail because it could not find the VAULT_TOKEN as an environment variable.
At first, it seemed easy to fix since, according to the sparse documentation on how to set environment variables in OPNsense, in System>Settings>Tunables, when a value is set without a parent, it would become an env variable. However, it did not work.
Another suggestion from a user in the OPNsense forum was to set the variable in /usr/local/opnsense/service/conf/configd.conf. It did not work either.

I have fixed the issue with the below changes.

1) OPNsense ACME Plugin Form


Let's add the VAULT_TOKEN field to the ACME plugin by adding the below lines to the following OPNsense files.

1.1) AcmeClient/forms/dialogAction.xml

Add the below under this line.

...
<field>
        <id>action.acme_vault_token</id>
        <label>Vault Token</label>
        <type>text</type>
        <help>This specifies the Vault token to authenticate with.</help>
</field>
...
/usr/local/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogAction.xml

1.2) AcmeClient/AcmeClient.xml

Add the below under this line.

...		
		<acme_vault_token type="TextField">
                    <Required>Y</Required>
                    <mask>/^.{1,1024}$/u</mask>
                    <ValidationMessage>Should be a string between 1 and 1024 characters.</ValidationMessage>
         </acme_vault_token>
...
/usr/local/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml

1.3) AcmeClient/LeAutomation/AcmeVault.php

Add the below under this line.

...
if (!empty((string)$this->config->acme_vault_token)) {
            $this->acme_env['VAULT_TOKEN'] = (string)$this->config->acme_vault_token;
}
...

With the above changes, the ACME Automation Form should appear as in the picture below. We implemented a field for the VAULT_TOKEN.

2) ACME Script Fix


After adding the above, the upload was still failing. The paths were being created empty.
When troubleshooting, I noticed that the vault.sh script removing new lines from the certificates was using the sed with the -z not available in the FreeBSD version of the tool. Therefore the value of the certificate was empty when uploaded.
With the help of our friend "chatty," changing the below lines fixed the parsing, and everything worked as intended.

...
  # JSON does not allow multiline strings.
  # So replacing new-lines with "\n" here
  _ckey=$(cat $2  | tr '\n' '\0' | sed 's/\n/\\n/g')
  _ccert=$(cat $3 | tr '\n' '\0' | sed 's/\n/\\n/g')
  _cca=$(cat $4 | tr '\n' '\0' | sed 's/\n/\\n/g')
  _cfullchain=$(cat $5 | tr '\n' '\0' | sed 's/\n/\\n/g')
  #_ckey=$(sed -z 's/\n/\\n/g' <"$2")
  #_ccert=$(sed -z 's/\n/\\n/g' <"$3")
  #_cca=$(sed -z 's/\n/\\n/g' <"$4")
  #_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
...
/usr/local/share/examples/acme.sh/deploy/vault.sh

3) Conclusion

With the above bugfix certificates will be uploaded to your vault instance.


Resources

OPNsense - environment variables

ACME - Hashicorp deploy certificates to Vault