CertIntel plugin for Posh-ACME¶
Requires Posh-ACME 4.7+ (4.x) and Windows PowerShell 5.1 or PowerShell 7. The plugin is
the single CertIntel.ps1 file, Posh-ACME's native plugin format.
No separate JSON configuration is needed. Pass delegation details as plugin
arguments and API keys as SecureString values. Posh-ACME saves the arguments
for renewal and protects secure values using the account's encryption settings.
It manages its own configuration files automatically.
Install¶
Install Posh-ACME first. Then download the plugin into a permanent folder outside the module directory, so module updates do not remove it. The release record points at the current version and carries each file's SHA-256, so nothing below hardcodes a version:
$release = Invoke-RestMethod 'https://api.certin.tel/api/v1/releases/plugin-posh-acme/latest.json'
$plugins = New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\CertIntel\Posh-ACME\Plugins"
foreach ($name in 'CertIntel.ps1', 'Get-CertIntelIisCertificate.ps1') {
$file = $release.files | Where-Object name -eq $name
$path = Join-Path $plugins $name
Invoke-WebRequest -Uri $file.url -OutFile $path
if ((Get-FileHash $path -Algorithm SHA256).Hash -ne $file.sha256) { throw "SHA-256 mismatch: $name" }
}
"Installed CertIntel plugin $($release.version) to $plugins"
Posh-ACME finds the plugin through POSHACME_PLUGINS. Set it for the current
session and persist it for future sessions, then import the module and confirm
the plugin loads:
$env:POSHACME_PLUGINS = "$env:LOCALAPPDATA\CertIntel\Posh-ACME\Plugins"
[Environment]::SetEnvironmentVariable('POSHACME_PLUGINS', $env:POSHACME_PLUGINS, 'User')
Import-Module Posh-ACME -Force
Get-PAPlugin CertIntel -Params
For an all-users installation, use a folder such as
$env:ProgramData\CertIntel\Posh-ACME\Plugins and persist the variable with the
'Machine' target from an elevated session. Scheduled renewal scripts must set
POSHACME_PLUGINS before importing Posh-ACME. PowerShell 7 users on other
platforms can substitute their own absolute paths. To upgrade later, run the
download block again. Both scripts are Authenticode-signed; see
Downloads for the signer thumbprint.
Create a delegation in CertIntel and its permanent CNAME at your DNS provider:
The page that follows shows, under Use this delegation with… → Posh-ACME,
the plugin arguments for your CertIntel deployment, ready to copy: the
Delegation ID, CNAME target and API base. Keep the update secret (shown once)
for the prompt. example.com and
*.example.com share one mapping. Other names require separate exact mappings.
Staging issuance without JSON¶
Set-PAServer LE_STAGE
$pluginArgs = @{
CertIntelDomain = 'example.com'
CertIntelDelegationId = '11111111-1111-1111-1111-111111111111'
CertIntelCnameTarget = 'YOUR-LABEL.dns01.certin.tel'
CertIntelApiKey = Read-Host 'CertIntel API key' -AsSecureString
}
New-PACertificate 'example.com','*.example.com' -Plugin CertIntel `
-PluginArgs $pluginArgs -DnsSleep 60 -AcceptTOS -Contact 'you@example.com'
The API endpoint defaults to https://api.certin.tel/api/v1. To override it,
add CertIntelApiBase = 'https://your-server.example/api/v1' to the hashtable;
on a private deployment always set it. Each call prints the API it uses, and says
when that is the default. An optional CertIntelLockDirectory sets where the plugin keeps its
per-delegation lock files (default .certintel-locks under Posh-ACME's
configuration root); it is required only when calling Add-DnsTxt directly
outside Posh-ACME.
Certificate hostnames must not contain underscores; the _acme-challenge record
prefix does contain a required underscore.
This performs DNS validation and writes Posh-ACME's certificate files without
installing them into a server. Confirm issuance and TXT cleanup. Increase
-DnsSleep if needed for DNS propagation.
Multiple delegations¶
Use arrays in matching domain order:
$pluginArgs = @{
CertIntelDomain = @('example.com', 'www.example.com')
CertIntelDelegationId = @(
'11111111-1111-1111-1111-111111111111'
'22222222-2222-2222-2222-222222222222'
)
CertIntelCnameTarget = @('FIRST-LABEL.dns01.certin.tel', 'SECOND-LABEL.dns01.certin.tel')
CertIntelApiKey = @(
(Read-Host 'API key for example.com' -AsSecureString)
(Read-Host 'API key for www.example.com' -AsSecureString)
)
}
New-PACertificate 'example.com','*.example.com','www.example.com' -Plugin CertIntel `
-PluginArgs $pluginArgs -DnsSleep 60 -AcceptTOS -Contact 'you@example.com'
CertIntelApiBase accepts one shared endpoint or one per domain.
Keep secure keys in the top-level CertIntelApiKey argument; do not put them in
nested hashtables or convert them to JSON.
Credential protection and vaults¶
On Windows, default DPAPI protection depends on the user and machine. Run renewals under the setup account. Linux/macOS users should enable Posh-ACME's alternative plugin encryption.
Posh-ACME 4.11+ can store its encryption key in a SecretManagement vault; API credentials remain encrypted in its order files. After installing SecretManagement and registering a writable vault:
For a new account, use New-PAAccount -AcceptTOS -Contact 'you@example.com' -UseAltPluginEncryption.
Verify account sskey is VAULT and VaultGuid is populated. If alternative
encryption was already enabled, follow the official migration steps. Renewals
need noninteractive vault access. See the
SecretManagement guide.
You can obtain the initial API key with Get-Secret if it returns a SecureString.
Posh-ACME saves that value; it is not a live reference to the individual API-key
secret. After rotating a key, update the selected order with the full argument
set using Set-PAOrder -PluginArgs $pluginArgs.
See also the plugin development guide.
Renewal and production¶
With the staging order selected, test renewal using Submit-Renewal -Force.
Saved plugin arguments are reused; no key prompt or JSON file editing is needed.
For production, select Set-PAServer LE_PROD and create a production order using
the same delegation arguments. A staging certificate is not publicly trusted.
A scheduled script should set POSHACME_PLUGINS, import Posh-ACME, select the
intended server, then run Submit-Renewal -AllAccounts. Set any vault or custom
POSHACME_HOME environment variables used during setup as well. Test the script
under the actual renewal account.
Locks default to .certintel-locks in Posh-ACME's configuration root. Use one
issuing client/host per delegation, with a consistent lock directory. Do not run
the dedicated CertIntel agent concurrently against the same delegation. The API
permits at most two TXT values and cannot protect against writers on other hosts.
Production and scheduled command examples¶
After the staging test, create the production order in the same PowerShell
session (using the $pluginArgs from setup):
Set-PAServer LE_PROD
New-PACertificate 'example.com','*.example.com' -Plugin CertIntel `
-PluginArgs $pluginArgs -DnsSleep 60 -AcceptTOS -Contact 'you@example.com'
For a Windows scheduled task, save the following as a script and run it with
PowerShell under the same Windows account used for setup. The
SetEnvironmentVariable line in Install already persists POSHACME_PLUGINS
for that account (default %LOCALAPPDATA%\CertIntel\Posh-ACME\Plugins, or
%ProgramData%\CertIntel\Posh-ACME\Plugins if you persisted it with the
'Machine' target), so the first line only matters if you installed the plugin
somewhere else. Choose a
regular schedule, such as twice daily:
$ErrorActionPreference = 'Stop'
if (-not $env:POSHACME_PLUGINS) { $env:POSHACME_PLUGINS = "$env:LOCALAPPDATA\CertIntel\Posh-ACME\Plugins" }
Import-Module Posh-ACME -MinimumVersion 4.7.0 -MaximumVersion 4.999.999 -Force
Set-PAServer LE_PROD
Submit-Renewal -AllAccounts
This renews certificate files when due. Configure a separate deployment step if your application needs certificate import, an IIS binding update or a reload.
Simple IIS certificate setup (Windows)¶
The download block in Install also placed Get-CertIntelIisCertificate.ps1
in the plugin folder. It is a one-shot helper for a single IIS site. It
requests a production Let's Encrypt certificate through the CertIntel plugin,
imports it into LocalMachine\My, and creates or updates the site's HTTPS
binding (*:443:<hostname> with SNI). It does not create a renewal task, so
you must renew and rebind before the certificate expires (for example with the
scheduled script above plus your own binding update).
Run it in Windows PowerShell 5.1 as administrator after installing the
plugin. Either edit the param block at the top (SiteName, Domain, Email,
DelegationId, CnameTarget; leave ApiBase unless you run a private
CertIntel) or pass the same names as parameters:
& "$env:POSHACME_PLUGINS\Get-CertIntelIisCertificate.ps1" -SiteName 'Default Web Site' `
-Domain 'www.example.com' -Email 'you@example.com' `
-DelegationId '11111111-1111-1111-1111-111111111111' `
-CnameTarget 'YOUR-LABEL.dns01.certin.tel'
It prompts for the delegation update secret without echo (or accepts -ApiKey
as a SecureString). It refuses to change IIS if the hostname is already bound
to another site, if an existing binding is not All Unassigned/443/SNI/local
store, or if issuance fails, and finishes with Done: https://<domain> is bound
to IIS site '<site>' using certificate <thumbprint>.
Optional CertIntel reporting¶
The DNS plugin does not send check-ins or renewal reports. Use the separate
Posh-ACME reporting wrappers
if you want those reports. They accept -PluginDirectory for custom plugin
discovery and -DirectoryUrl LE_PROD (or LE_STAGE) to select the CA. The issuance
wrapper takes -Plugin CertIntel -PluginArgs $pluginArgs -DnsSleep 60.
Schedule the renewal wrapper in place of the direct command above; it processes
the current account's orders. Set the same account, configuration root and vault
environment used at setup. Its write-scoped reporting key is separate from the
DNS plugin's delegation credential.
Troubleshooting¶
| Symptom | Check |
|---|---|
CertIntel is missing from Get-PAPlugin |
Set POSHACME_PLUGINS before importing Posh-ACME with -Force; verify the renewal account can read CertIntel.ps1. |
| No delegation matches | Use the exact certificate name without *. or _acme-challenge.; subdomains need their own mapping. |
| API 401/403 | Check the update secret, delegation status and API endpoint. |
| Saved secret cannot be decrypted | Run as the setup account on the same Windows machine, or restore access to the configured alternative encryption key/vault. |
| DNS validation fails | Verify the permanent CNAME and public TXT answers; increase -DnsSleep if necessary. |
| Two TXT values already exist | Confirm no other client is issuing; remove stale values only after confirming no issuance is active. |