Skip to content

realworldtech/wincertmanager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Windows Certificate Manager Toolkit

A toolkit for automating SSL certificate management on Windows Servers (2012+) using Let's Encrypt via win-acme.

Supported Services

  • IIS - Automatic HTTPS binding for websites
  • RD Gateway - Remote Desktop Gateway SSL certificates
  • LDAPS - Domain Controller LDAP over SSL

Quick Start

0. Download the Toolkit

Download the latest signed release from GitHub Releases:

  1. Download wincertmanager-x.x.x.zip and wincertmanager-x.x.x.zip.sha256
  2. Verify the SHA256 checksum
  3. Extract to C:\Tools\wincertmanager (or your preferred location)
  4. (Optional) To trust the toolkit's code-signing certificate for signature validation:
    Import-Certificate -FilePath C:\Tools\wincertmanager\certs\rwts-codesign.cer -CertStoreLocation Cert:\LocalMachine\Root
    Note: Using LocalMachine\Root ensures full trust for signature validation. The LocalMachine store ensures the SYSTEM account (used for scheduled renewals) also trusts the certificate.

1. Prepare the Server

# Run prerequisites check and installation
.\scripts\Prerequisites\Install-Prerequisites.ps1

This will:

  • Check Windows version and requirements
  • Enable TLS 1.2 if needed
  • Verify .NET Framework version
  • Download and install win-acme to C:\Tools\win-acme
  • Create renewal scheduled task

Custom install path:

.\scripts\Prerequisites\Install-Prerequisites.ps1 -InstallPath "$env:ProgramFiles\win-acme"

2. Configure DNS Validation (acme-dns)

# Register domain with acme-dns
.\scripts\AcmeDns\Register-AcmeDns.ps1 -Domain "server.example.com"

# Add the CNAME record shown in the output to your DNS provider
# _acme-challenge.server.example.com -> <subdomain>.auth.acme-dns.io

3. Request Certificate

Example for LDAPS on a Domain Controller:

C:\Tools\win-acme\wacs.exe `
    --source manual --host dc01.example.com `
    --validation script `
    --dnscreatescript "C:\Tools\wincertmanager\scripts\AcmeDns\Update-AcmeDnsTxt.ps1" `
    --dnscreatescriptarguments "create {Identifier} {RecordName} {Token}" `
    --store certificatestore --certificatestore My `
    --installation script `
    --script "C:\Tools\wincertmanager\scripts\PostRenewal\Update-LDAPS.ps1" `
    --scriptparameters "-Thumbprint {CertThumbprint} -TestConnection" `
    --accepttos --emailaddress admin@example.com

See Service-Specific Notes for IIS and RD Gateway examples.

Project Structure

wincertmanager/
├── scripts/
│   ├── Prerequisites/          # Server preparation and win-acme installation
│   │   ├── Install-Prerequisites.ps1
│   │   └── Test-ServerReadiness.ps1
│   ├── AcmeDns/               # acme-dns registration and credential management
│   │   ├── Register-AcmeDns.ps1
│   │   ├── Get-AcmeDnsCredential.ps1
│   │   └── Update-AcmeDnsTxt.ps1   # DNS validation script for win-acme
│   ├── PostRenewal/           # Service-specific certificate binding scripts
│   │   ├── Update-RDGateway.ps1
│   │   └── Update-LDAPS.ps1
│   ├── Logging/               # Central logging functionality
│   │   └── Send-CertificateEvent.ps1
│   └── Helpers/               # Shared functions
│       └── Common.ps1
├── config/                    # Configuration templates
│   ├── logging-config.example.json
│   ├── acme-dns/
│   └── cloudflare/
├── docs/                      # Setup guides
│   ├── customer-onboarding.md
│   ├── iis-setup.md
│   ├── rdgateway-setup.md
│   ├── ldaps-setup.md
│   └── troubleshooting.md
└── examples/                  # win-acme configuration examples
    ├── win-acme-iis.txt
    ├── win-acme-rdgateway.txt
    └── win-acme-ldaps.txt

Requirements

Requirement Minimum Recommended
Windows Server 2012 2016+
.NET Framework 4.6.2 4.7.2+
PowerShell 5.0 5.1

DNS Validation Methods

acme-dns (Recommended)

acme-dns delegates only the ACME challenge subdomain, providing:

  • No full DNS provider access needed
  • Works with any DNS provider supporting CNAME
  • Simple one-time CNAME setup
  • Works reliably on Domain Controllers and internal servers

Public acme-dns server: https://auth.acme-dns.io

You can also run your own acme-dns server or use a third-party hosted one.

Setup Steps

  1. Register with acme-dns:

    # Using the public acme-dns server (default)
    .\scripts\AcmeDns\Register-AcmeDns.ps1 -Domain "server.example.com"
    
    # Or specify a custom acme-dns server with API authentication
    .\scripts\AcmeDns\Register-AcmeDns.ps1 -Domain "server.example.com" `
        -AcmeDnsServer "https://acme-dns.example.com" `
        -ApiKey "your-api-key" -ApiKeyId "your-key-id"
  2. Add the CNAME record shown in the output to your DNS:

    _acme-challenge.server.example.com. CNAME <subdomain>.auth.acme-dns.io.
    
  3. Request certificate using the script validation method (see examples below)

Script-Based Validation

This toolkit uses script-based DNS validation with win-acme rather than win-acme's built-in acme-dns plugin. This approach:

  • Works reliably in unattended/automated scenarios
  • Uses WinCertManager's secure DPAPI-encrypted credential storage
  • Avoids issues with win-acme's preliminary DNS validation on Domain Controllers

The Update-AcmeDnsTxt.ps1 script reads the acme-dns server URL from the stored credentials, so it works with any acme-dns server you registered with.

CloudFlare

Direct CloudFlare API integration:

  • Requires CloudFlare-managed DNS
  • Create API token with Zone > DNS > Edit permission
  • Automatic record creation/cleanup

Service-Specific Notes

IIS

win-acme has native IIS support. No post-renewal script needed - win-acme handles binding updates automatically.

wacs.exe --source iis --siteid 1 `
    --validation script `
    --dnscreatescript "C:\Tools\wincertmanager\scripts\AcmeDns\Update-AcmeDnsTxt.ps1" `
    --dnscreatescriptarguments "create {Identifier} {RecordName} {Token}" `
    --installation iis

RD Gateway

Requires post-renewal script to update SSL binding:

wacs.exe --source manual --host gateway.example.com `
    --validation script `
    --dnscreatescript "C:\Tools\wincertmanager\scripts\AcmeDns\Update-AcmeDnsTxt.ps1" `
    --dnscreatescriptarguments "create {Identifier} {RecordName} {Token}" `
    --store certificatestore --certificatestore My `
    --installation script `
    --script "C:\Tools\wincertmanager\scripts\PostRenewal\Update-RDGateway.ps1" `
    --scriptparameters "-Thumbprint {CertThumbprint} -RestartService"

LDAPS

Active Directory automatically detects certificates with Server Authentication EKU. The post-renewal script verifies configuration:

wacs.exe --source manual --host dc01.example.com `
    --validation script `
    --dnscreatescript "C:\Tools\wincertmanager\scripts\AcmeDns\Update-AcmeDnsTxt.ps1" `
    --dnscreatescriptarguments "create {Identifier} {RecordName} {Token}" `
    --store certificatestore --certificatestore My `
    --installation script `
    --script "C:\Tools\wincertmanager\scripts\PostRenewal\Update-LDAPS.ps1" `
    --scriptparameters "-Thumbprint {CertThumbprint} -TestConnection"

Note: Internal-only domains (.local) cannot use Let's Encrypt. Use a publicly resolvable domain (e.g., dc01.internal.example.com where example.com is a real domain you control).

Monitoring

Windows Event Log

All certificate events are logged to Windows Event Log:

  • Source: WinCertManager
  • Log: Application

Central Logging (Optional)

Configure config/logging-config.json for:

  • Webhook notifications (HTTP POST)
  • Syslog forwarding (UDP/TCP)

Troubleshooting

Run the readiness check:

.\scripts\Prerequisites\Test-ServerReadiness.ps1 -Detailed

Domain Controllers and Internal DNS

When running on a Domain Controller or server using internal DNS, win-acme's preliminary DNS validation may fail because the internal DNS cannot resolve external acme-dns subdomains.

Symptom: Win-acme shows "Preliminary validation failed" even though the TXT record was created successfully.

Solution: Configure win-acme to use public DNS servers for validation. Edit C:\Tools\win-acme\settings.json:

"Validation": {
    "DnsServers": [ "8.8.8.8", "1.1.1.1" ],
    ...
}

This tells win-acme to use Google/Cloudflare DNS for checking TXT records instead of the system's DNS.

Renewals Silently Failing (Legacy DPAPI Scope)

Toolkit versions ≤ v1.0.3 stored acme-dns credentials using DPAPI in CurrentUser scope, but the win-acme renewal scheduled task runs as SYSTEM. SYSTEM cannot decrypt CurrentUser-scoped DPAPI blobs, so every automatic renewal fails inside Get-AcmeDnsCredential.ps1 and the certificate eventually expires without anyone being paged.

Symptoms:

  • Get-ScheduledTask -TaskName 'win-acme*' | Get-ScheduledTaskInfo shows LastTaskResult of 4294967295 (0xFFFFFFFF)
  • %ProgramData%\win-acme\acme-v02.api.letsencrypt.org\Log\log-*.txt contains ConvertTo-SecureString : ... CryptographicException and Failed to decrypt password. This usually means the credential was stored by a different user or on a different machine.
  • The credential JSON in %ProgramData%\WinCertManager\Config\acme-dns\ reports "StorageMethod": "DPAPI"

Fix: scripts/Recovery/Repair-AcmeDnsCredential.ps1 re-encrypts the credential under DPAPI LocalMachine scope (so SYSTEM can decrypt it) without changing the acme-dns subdomain registration — no DNS changes required. Run it once per affected host as the same admin that originally registered the domain; the script then recovers the password from the existing DPAPI blob automatically, so you don't need it from a password manager. It also clears any stale win-acme ARI cache entries that may be holding a "replacement" slot for the failed cert and offers to run the renewal interactively. Toolkit ≥ v1.0.4 stores new credentials in LocalMachine scope by default, so fresh installs are unaffected.

Verify the script before running it. Open it in a text editor or run Get-AuthenticodeSignature against a copy from a signed release ZIP. If you're running as a different operator from the one that originally registered the domain, the script will fall back to prompting for the password field returned by /register (retrievable from your password manager).

# On the affected host, in an elevated PowerShell session,
# signed in as the admin that originally registered the domain:
$url = 'https://raw.githubusercontent.com/realworldtech/wincertmanager/main/scripts/Recovery/Repair-AcmeDnsCredential.ps1'
$dest = Join-Path $env:TEMP 'Repair-AcmeDnsCredential.ps1'
Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing

# REVIEW the file before executing:
notepad $dest

# Then run for the affected domain. Auto-recovers the password,
# clears the ARI cache, and prompts to run wacs.exe --renew:
& $dest -Domain 'dc01.internal.example.com'

If you prefer a signed copy, download the latest release ZIP from the Releases page, verify the SHA256, and run the script from scripts/Recovery/ inside the extracted directory.

See docs/troubleshooting.md for more common issues.

Documentation

Guide Description
Customer Onboarding Setup guide and decision tree
IIS Setup IIS certificate automation
RD Gateway Setup Remote Desktop Gateway certificates
LDAPS Setup Domain Controller LDAPS certificates
Troubleshooting Common issues and solutions

Key Paths

Component Default Location Configurable
win-acme C:\Tools\win-acme Yes (-InstallPath)
win-acme Config %ProgramData%\win-acme Via win-acme settings
WinCertManager Toolkit C:\Tools\wincertmanager Manual (copy anywhere)
WinCertManager Config %ProgramData%\WinCertManager\Config No
WinCertManager Logs %ProgramData%\WinCertManager\Logs No

Certificate Renewal

Certificates are renewed automatically:

  • Scheduled task runs daily at 9:00 AM
  • Renewal triggered when < 30 days remain
  • Let's Encrypt certificates valid for 90 days

Check scheduled task status:

Get-ScheduledTask -TaskName "win-acme renew" | Get-ScheduledTaskInfo

Security Considerations

  1. DNS Validation: Preferred over HTTP-01 for internal servers
  2. Credential Storage: DPAPI encryption for acme-dns credentials
  3. API Tokens: Use minimal permissions (zone-specific, DNS Edit only)
  4. Private Keys: Stored in Windows certificate store with appropriate ACLs

Contributing

This toolkit is maintained by Real World Technology Solutions.

License

This project is licensed under CC BY-NC 4.0 (Creative Commons Attribution-NonCommercial 4.0).

References

About

Windows Certificate Manager Toolkit - Automated SSL certificate management for Windows Server using Let's Encrypt via win-acme

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors