Add Repair-AcmeDnsCredential recovery tool for DPAPI scope mismatch#7
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a recovery workflow to fix existing WinCertManager acme-dns credential files that were encrypted with DPAPI CurrentUser scope (interactive registration) but later need to be decrypted by the SYSTEM-run renewal scheduled task.
Changes:
- Introduces a self-contained recovery script that re-encrypts an existing acme-dns credential password using DPAPI
LocalMachinescope and updates the credential JSON accordingly. - Implements an idempotent local patch mechanism to extend
Get-AcmeDnsCredential.ps1with support for a newDPAPI-LocalMachineStorageMethod, including backups and verification.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4 tasks
Register-AcmeDns.ps1 encrypts the acme-dns password using DPAPI in CurrentUser scope, but Install-Prerequisites.ps1 creates the renewal scheduled task running as SYSTEM. SYSTEM cannot decrypt CurrentUser DPAPI blobs, so every automatic renewal fails until the certificate expires. This recovery tool re-encrypts an existing credential file under DataProtectionScope.LocalMachine so any account on the host (including SYSTEM) can decrypt it. The script auto-detects the toolkit, patches the local Get-AcmeDnsCredential.ps1 to recognise the new "DPAPI-LocalMachine" StorageMethod, backs up both files, and verifies the round-trip end-to-end. Verified end-to-end on a Domain Controller affected by this bug: the repair tool was applied, then the win-acme renewal scheduled task running as SYSTEM successfully renewed the certificate. A toolkit-level fix making LocalMachine scope the default for new registrations will follow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a 'Renewals Silently Failing (Legacy DPAPI Scope)' subsection to the README troubleshooting block describing the symptom (renewal task exit code 0xFFFFFFFF, decrypt failure in win-acme logs, StorageMethod "DPAPI" in the credential JSON) and the recovery procedure. The procedure downloads the script from raw.githubusercontent.com, explicitly opens it for review before execution, and prompts for the original acme-dns password. Also points operators at the signed release ZIP for verified deployment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1003783 to
2d9add0
Compare
Makes -Domain optional. When omitted, the script enumerates the credential store directory (default %ProgramData%\WinCertManager\Config\acme-dns) and uses the single credential file present. If zero or multiple files exist, the script errors with a clear message listing the candidates. Motivation: enables running the recovery as a single unattended job from an RMM platform without per-host customisation. The new Resolve-DomainFromCredentialStore helper excludes .meta.json files (Credential Manager metadata) so it interacts cleanly with both storage methods. Verified on a host where the credential is already migrated: auto-detect picks the correct file, the rest of the workflow proceeds unchanged, and -WhatIf prevents writes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scripts/Recovery/Repair-AcmeDnsCredential.ps1, a self-contained recovery tool that re-encrypts an existing acme-dns credential file underDataProtectionScope.LocalMachineso the SYSTEM-context win-acme renewal task can decrypt it.Get-AcmeDnsCredential.ps1to recognise the newDPAPI-LocalMachineStorageMethod, and backs up both files before writing.Get-AcmeDnsCredential.ps1before declaring success.Why
Register-AcmeDns.ps1encrypts the acme-dns password using DPAPI in CurrentUser scope (line 195), butInstall-Prerequisites.ps1creates the renewal scheduled task running as SYSTEM (line 382). SYSTEM cannot decrypt CurrentUser-scoped DPAPI blobs, so every automatic renewal fails silently until the certificate expires. We hit this in production today — first renewal cycle since deployment, cert expired before the scheduled task could renew it.This is a recovery tool to unstick existing deployments. A follow-up PR will change
Register-AcmeDns.ps1to writeDPAPI-LocalMachineby default for new registrations.Test plan
Get-AcmeDnsCredential.ps1parses cleanly via[Parser]::ParseFile-WhatIfdry run on test server resolves toolkit + credential paths and round-trips DPAPICo-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com