Posh-ACME 4.0.0
HTTP plugins, portable plugin arg encryption, better help
Just shipped a new Posh-ACME release, version 4.0.0. This is a huge personal win for me that took far longer than I had originally intended. So I’m super excited to finally get it out the door.
HTTP Plugins
The biggest long overdue change is that the plugin system can now support http-0 based challenges and the architecture has been revamped such that adding support for additional challenge types should be significantly easier. There are only two built-in HTTP plugins at the moment: WebRoot and WebSelfHost. WebRoot is basically a file copy plugin that works with any web server that hosts files directly from a filesystem location. WebSelfHost is a plugin-ized version of the existing Invoke-HttpChallengeListener function that directly hosts the challenge files without needing a separate web server.
Plugin Args
Another big internal change is how plugin args are stored on disk. Previously, they were stored per-account and serialized using PowerShell’s native Import-CliXml/Export-CliXml functions which allowed for easy encryption of SecureString and PSCredential parameters, but only on Windows. On non-Windows, the values are only mildly obfuscated. In 4.0, they are now stored per-order and serialized to JSON using a semi-manual process and the secure parameters are serialized using ConvertTo-SecureString/ConvertFrom-SecureString which gave me the flexibility to add an OS-agnostic AES encryption key.
On Windows by default, plugin parameters are still encrypted using the OS native user/machine specific DPAPI process. However, you can now choose to use a portable, randomized 256-bit AES key instead via the UseAltPluginEncryption switch which is configurable per ACME account. It works like this:
# If you don't already have an ACME account
New-PAAccount -AcceptTOS -UseAltPluginEncryption -Contact 'me@example.com'
# To enable on an existing account
Set-PAAccount -UseAltPluginEncryption
# To disable/revert on an existing account
Set-PAAccount -UseAltPluginEncryption:$false
For now, the key is stored in the account config. But I’m hoping to add support for storing the key using the SecretManagement modules once they reach a more stable state.
The new per-order storage of the plugin args makes things slightly more cumbersome if you’re managing multiple different certs with the same set of plugins because you now have to manage those args separately for each order. However, there’s a new Get-PAPluginArgs function that can help ease that burden. Let’s say you’re creating a new certificate that will be using the same Azure plugin as a previous certificate. Instead of needing go lookup the plugin args and re-build the hashtable, you can do this instead.
# Get a copy of the args for the old order
$pArgs = Get-PAPluginArgs example.com
# Create the new cert
New-PACertificate example2.com -Plugin Azure -PluginArgs $pArgs
Better In-Module Help
Despite my efforts to maintain robust function-specific help, the one thing I found myself constantly going back to the wiki for is a quick reference for what arguments a specific plugin needed. Not only did it annoy me to need to open a browser at all, I then had to navigate to that plugin’s specific user guide. So I scrapped the old Get-DnsPlugins and Get-DnsPluginHelp functions and replaced them with a single Get-PAPlugin command. In particular, this new function has a -Guide and -Params switch. The guide switch on Windows will launch your default browser to that plugin’s user guide (non-Windows for the time being will just display the URL). The params switch will display a nicely formatted quick reference of the available plugin parameters. Here’s the current output for the Route53 plugin.
PS C:\> Get-PAPlugin Route53 -Params
Set Name: Keys (Default)
Parameter Type IsMandatory
--------- ---- -----------
R53AccessKey String True
R53SecretKey SecureString True
Set Name: KeysInsecure
Parameter Type IsMandatory
--------- ---- -----------
R53AccessKey String True
R53SecretKeyInsecure String True
Set Name: Profile
Parameter Type IsMandatory
--------- ---- -----------
R53ProfileName String True
Set Name: IAMRole
Parameter Type IsMandatory
--------- ---- -----------
R53UseIAMRole SwitchParameter True
Other Quality of Life Improvments
There is now an AlwaysNewKey switch for all of the functions that deal with orders to indicate you want a new private key generated on renewals. A UseSerialValidation switch has been also been to order related functions which tells the validation process to publish and validate each challenge individually rather than at the same time which is useful for providers like DuckDNS.
BUYPASS_PROD and BUYPASS_TEST have been added as shortcuts for buypass.com in Set-PAServer. ZEROSSL_PROD has been similarly added for zerossl.com.
Posh-ACME will now properly handle ACME orders with IP address identifiers based on RFC 8738. However, I don’t think there are any ACME CAs that allow this just yet. Also keep in mind that certs for IPs can only be validated using the http-01 or tls-alpn-01 challenge types.
Posh-ACME now also supports ECC P-521 based keys for accounts and certificates using the ec-521 key length parameter. However, this is another thing that needs to be supported by the ACME server as well and Let’s Encrypt currently does not support it.
Updated versions can be found in the PowerShell Gallery or GitHub. Installation instructions are in the Readme.
Changelog
There is a 3.x to 4.x migration guide in the FAQ on the wiki. But no changes should be necessary for users with existing certs that are renewing using Submit-Renewal unless they were also using the -NewKey parameter which has been removed. Orders can now be configured to always generate a new private key using Set-PAOrder -AlwaysNewKey.
New Features
- The DNS plugin system has been revamped to support both dns-01 and http-01 challenges. (#124)
- All existing DNS plugins have been upgraded to the new plugin format. See the README in the plugins folder for details and instructions on how to upgrade your own custom plugins.
- There are two new http-01 challenge plugins called
WebRootandWebSelfHost. See their usage guides for details.
- Plugin args are now saved per-order rather than per-account and as JSON rather than XML.
- This has the side effect that new orders using the same plugin(s) as a previous order will no longer reuse the previous args.
- Added
Get-PAPluginArgswhich returns a hashtable with the plugin args associated with the current or specified order. You can use this to retrieve another order’s plugin args and use that object with your new order. - Pre-4.x plugin args will be automatically migrated to per-order plugin args the first time an account is selected using
Set-PAAccountor on module load for the last selected account. The old file will be backed up with a “.v3” extension in case you need to revert.
- Portable, Cross-Platform encryption is now supported for secure plugin parameters on disk and can be configured on a per-account basis. It is based on a 256-bit AES key generated for the account. This makes it possible to migrate a Posh-ACME config between users, machines, or OSes without needing to re-configure secure plugin args. (#150)
- To enable, set the
UseAltPluginEncryptionswitch onNew-PAAccountorSet-PAAccount. This will immediately re-encrypt plugin args for all orders associated with the account. - To disable/revert, run
Set-PAAccount -UseAltPluginEncryption:$false. - If you believe the encryption key has been compromised, use
Set-PAAccount -ResetAltPluginEncryptionto generate a new key and re-encrypt everything.
- To enable, set the
Get-PAPluginis a new function that replacesGet-DnsPluginsandGet-DnsPluginHelp.- With no parameters, lists all plugins and their details
- With a plugin parameter, shows the details for just that plugin
- With a plugin and
-Help, shows the plugin’s help - With a plugin and
-Guide, opens the default browser to the plugin’s online guide - With a plugin and
-Params, displays the plugin-specific parameter sets (#151)
- Added
AlwaysNewKeyswitch toNew-PACertificate,New-PAOrder, andSet-PAOrder. This flag tells Posh-ACME to always generate a new private key on renewals. The old parameters for key replacement have been removed. (#181) - Added
UseSerialValidationswitch toNew-PACertificate,New-PAOrder, andSet-PAOrder. This flag tells Posh-ACME to process the order’s authorization challenges serially rather than in parallel. This is primarily useful for providers like DuckDNS that only allow a single TXT record to be written at a time. - Added
Complete-PAOrderwhich does the final processing steps like downloading the signed cert and updating renewal window for an order that has reached the ‘ready’ state. This avoids the need to useNew-PACertificatewhen doing custom certificate workflows. - The PfxPass parameter on order objects is now obfuscated when serialized to disk. (#207)
- Added
PfxPassSecure(SecureString) parameter toNew-PACertificate,New-PAOrder, andSet-PAOrderwhich takes precedence overPfxPassif specified. (#207) - Added
DnsAliasandOCSPMustStapleparameters toSet-PAOrder. Changing an order’s OCSPMustStaple value will throw a warning that it only affects future certificates generated from the order. - Added
Plugin,PluginArgs,DnsAlias,DnsSleep, andValidationTimeoutparameters toNew-PAOrder. - The
DirectoryUrlparameter inSet-PAServeris now optional. If not specified, it will use the currently active server. - An attempt will now be made to send anonymous telemetry data to the Posh-ACME team when
Submit-OrderFinalizeis called directly or indirectly.- The only data sent is the standard HTTP User-Agent header which includes the Posh-ACME version, PowerShell version, and generic OS platform (Windows/Linux/MacOS/Unknown).
- This can be disabled per ACME server using a new
DisableTelemetryparameter inSet-PAServer. - The data will be used to guide future development decisions in the module.
- The same User-Agent header is also sent with all calls to the ACME server which is a requirement of the protocol and can’t be disabled.
- Added
NoRefreshswitch toSet-PAServerwhich prevents a request to the ACME server to update endpoint and nonce info. This is useful for updating local preferences without making a server round-trip. - BUYPASS_PROD and BUYPASS_TEST are now recognized shortcuts for the the buypass.com CA environments when you use
Set-PAServer. - ZEROSSL_PROD is now a recognized shortcut for the zerossl.com CA when you use
Set-PAServer. - Added tab completion for
DirectoryUrlinSet-PAServer. - Added
Quietparameter toGet-PAServerwhich will prevent warnings if the specified server was not found. Remove-PAServerwill now throw a warning instead of an error if the specified server doesn’t exist on disk.- Orders can now be passed by pipeline to
Submit-ChallengeValidationandSubmit-OrderFinalize. - ACME protocol web request details have been moved from Verbose to Debug output and cleaned up so they’re easier to follow. Web requests made from plugins will still be in Verbose output for the time being.
- Experimental support for IP address identifiers (RFC 8738) in new orders. This allows you to get a cert for an IP address if your ACME server supports it.
- Private keys for Accounts and Certificates can now use ECC P-521 (secp521r1) based keys using the
ec-521key length parameter. This requires support at the ACME server level as well.
Breaking Changes
- Function Changes
Publish-DnsChallengeis nowPublish-ChallengeUnpublish-DnsChallengeis nowUnpublish-ChallengeSave-DnsChallengeis nowSave-ChallengeGet-DnsPluginsandGet-DnsPluginHelphave been replaced byGet-PAPluginGet-PAAuthorizationsis nowGet-PAAuthorization. The plural function name is still avaialble as an alias but is deprecated and may be removed in a future release.Invoke-HttpChallengeListeneris deprecated and may be removed in a future release. Users should migrate to theWebSelfHostplugin.
- Parameter Changes
- All
DnsPluginparameters are nowPluginwith aDnsPluginalias for backwards compatibility. The alias should be considered deprecated and may be removed in a future release. - The
NoPrefixswitch in Publish/Unpublish-Challenge has been replaced with aDnsAliasparameter that will override theDomainparameter if specified. “_acme-challenge.” will not be automatically added to theDnsAliasparameter. NewKeyhas been removed fromSubmit-RenewalNewKey/NewCertKeyhave been replaced byAlwaysNewKeyinNew-PACertificateandNew-PAOrderAlwaysNewKeyhas been added toSet-PAOrderDnsPlugin,PluginArgs,DnsAlias,DnsSleep,ValidationTimeoutandAccountparameters have been removed fromSubmit-ChallengeValidation. The account associated with the order must be the currently active account. The rest of the parameters are read directly from the order object and can be modified in advance withSet-PAOrderif necessary.Accountparameter has been removed fromSubmit-OrderFinalize. The account associated with the order must be the currently active account.
- All
Fixes
- Using
Get-PAOrderwith-Refreshwill no longer throw a terminating error if the ACME server returns an error. It will warn and return the cached copy of the order instead. - Fixed
Remove-PAServernot being able to remove a server that is unreachable. Remove-PAServerno longer requires confirmation when there are no cached accounts associated with the specified server in the local config.
