certificate: enroll against AD CS natively over LDAP and MS-ICPR - #1449
certificate: enroll against AD CS natively over LDAP and MS-ICPR#1449denisonbarbosa wants to merge 9 commits into
Conversation
0be383b to
e030c17
Compare
e030c17 to
4f30a54
Compare
There was a problem hiding this comment.
Pull request overview
Adds native AD CS certificate enrollment through LDAP/GSSAPI and MS-ICPR while preserving CEPCES compatibility.
Changes:
- Adds certificate discovery, ACL evaluation, enrollment, renewal, state, and trust management.
- Plumbs backend selection through daemon and policy-manager configuration.
- Expands certificate documentation, dependencies, and automated coverage.
Reviewed changes
Copilot reviewed 78 out of 117 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
cmd/adsysd/daemon/daemon.go |
Adds enrollment configuration. |
cmd/adsysd/integration_tests/adsys_test.go |
Extends integration setup. |
cmd/adsysd/integration_tests/adsysctl_policy_test.go |
Splits certificate scenarios. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/apparmor.d/adsys/machine/nested/usr.bin.baz |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/apparmor.d/adsys/machine/usr.bin.bar |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/apparmor.d/adsys/machine/usr.bin.foo |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/apparmor.d/adsys/users/adsystestuser@example.com |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/dconf/db/gdm.d/adsys |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/dconf/db/gdm.d/locks/adsys |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/dconf/db/machine.d/adsys |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/dconf/db/machine.d/locks/adsys |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/dconf/profile/gdm |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/lib/private |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/lib/samba/cert_gpo_state_HOST.tdb |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/polkit-1/localauthority.conf.d/.empty |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/polkit-1/rules.d/00-adsys-privilege-enforcement.rules |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/.ready |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/empty-subfolder/.empty |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/final-machine-script.sh |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/other-script-user-logon |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/otherfolder/script-user-logoff |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/script-machine-shutdown |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/script-machine-startup |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/script-user-logon |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/subfolder/other-script |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/unreferenced-data |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/scripts/unreferenced-script |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/machine/scripts/startup |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/run/users/.empty |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/sudoers.d/99-adsys-privilege-enforcement |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_cepces_is_not_available/systemd/system/.empty |
Updates CEPCES golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/apparmor.d/adsys/machine/nested/usr.bin.baz |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/apparmor.d/adsys/machine/usr.bin.bar |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/apparmor.d/adsys/machine/usr.bin.foo |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/apparmor.d/adsys/users/adsystestuser@example.com |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/dconf/db/gdm.d/adsys |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/dconf/db/gdm.d/locks/adsys |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/dconf/db/machine.d/adsys |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/dconf/db/machine.d/locks/adsys |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/dconf/profile/gdm |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/lib/private |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/lib/samba/cert_gpo_state_HOST.tdb |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/polkit-1/localauthority.conf.d/.empty |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/polkit-1/rules.d/00-adsys-privilege-enforcement.rules |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/.ready |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/empty-subfolder/.empty |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/final-machine-script.sh |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/other-script-user-logon |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/otherfolder/script-user-logoff |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/script-machine-shutdown |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/script-machine-startup |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/script-user-logon |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/subfolder/other-script |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/unreferenced-data |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/scripts/unreferenced-script |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/machine/scripts/startup |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/run/users/.empty |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/sudoers.d/99-adsys-privilege-enforcement |
Updates certmonger golden. |
cmd/adsysd/integration_tests/testdata/TestPolicyUpdate/golden/does_not_error_when_certmonger_is_not_available/systemd/system/.empty |
Updates certmonger golden. |
conf.example/adsys.yaml |
Documents backend setting. |
docs/.custom_wordlist.txt |
Adds certificate terminology. |
docs/explanation/certificates.md |
Explains native enrollment. |
docs/how-to/certificates/configure.md |
Documents configuration. |
docs/how-to/certificates/index.md |
Adds certificate navigation. |
docs/how-to/certificates/setup.md |
Documents AD CS setup. |
docs/how-to/certificates/troubleshoot.md |
Adds troubleshooting guidance. |
docs/how-to/certificates/vpn.md |
Documents VPN usage. |
docs/index.md |
Links certificate documentation. |
docs/reference/adsysd-cli.md |
Updates daemon reference. |
docs/reference/external-links.md |
Adds external references. |
go.mod |
Adds LDAP/RPC dependencies. |
go.sum |
Records dependency checksums. |
internal/adsysservice/adsysservice.go |
Plumbs backend selection. |
internal/consts/consts.go |
Defines enrollment constants. |
internal/policies/certificate/access.go |
Evaluates template ACLs. |
internal/policies/certificate/access_test.go |
Tests ACL evaluation. |
internal/policies/certificate/binding.go |
Validates artifact ownership. |
internal/policies/certificate/cert-autoenroll |
Retains legacy CEPCES helper. |
internal/policies/certificate/cert-autoenroll_test.go |
Tests legacy helper behavior. |
internal/policies/certificate/certificate.go |
Orchestrates enrollment lifecycle. |
internal/policies/certificate/certificate_test.go |
Tests policy enrollment. |
internal/policies/certificate/chain.go |
Discovers and verifies CA chains. |
internal/policies/certificate/chain_test.go |
Tests chain handling. |
internal/policies/certificate/directory.go |
Models directory discovery. |
internal/policies/certificate/enroll.go |
Processes issued certificates. |
internal/policies/certificate/enroll_test.go |
Tests issuance processing. |
internal/policies/certificate/generation.go |
Publishes key/certificate pairs. |
internal/policies/certificate/generation_reconcile.go |
Reconciles interrupted publications. |
internal/policies/certificate/generation_test.go |
Tests atomic publication. |
internal/policies/certificate/gssapi.go |
Implements GSSAPI binding. |
internal/policies/certificate/gssapi_test.go |
Tests GSSAPI tokens. |
internal/policies/certificate/kdc_dialer.go |
Adds context-aware KDC I/O. |
internal/policies/certificate/kdc_dialer_test.go |
Tests KDC cancellation. |
internal/policies/certificate/krb5_config.go |
Configures Kerberos discovery. |
internal/policies/certificate/ldap.go |
Implements LDAP discovery. |
internal/policies/certificate/ldap_test.go |
Tests LDAP and bootstrap trust. |
internal/policies/certificate/lifecycle.go |
Handles issuance and polling. |
internal/policies/certificate/lifecycle_test.go |
Tests enrollment lifecycle. |
internal/policies/certificate/manage.go |
Adds management operations. |
internal/policies/certificate/manage_test.go |
Tests management operations. |
internal/policies/certificate/options_test.go |
Tests backend normalization. |
internal/policies/certificate/pending.go |
Persists pending requests. |
internal/policies/certificate/request.go |
Implements MS-ICPR requests. |
internal/policies/certificate/state.go |
Stores enrollment state. |
internal/policies/certificate/state_binding_test.go |
Tests state ownership. |
internal/policies/certificate/template.go |
Selects eligible templates. |
internal/policies/certificate/template_test.go |
Tests template eligibility. |
internal/policies/certificate/testdata/TestApplyPolicyCEPCES/golden/computer,_configured_to_enroll |
Updates CEPCES golden. |
internal/policies/certificate/testdata/TestApplyPolicyCEPCES/golden/computer,_configured_to_enroll,_advanced_configuration |
Updates CEPCES golden. |
internal/policies/certificate/testdata/TestApplyPolicyCEPCES/golden/computer,_configured_to_unenroll |
Updates CEPCES golden. |
internal/policies/certificate/testdata/TestApplyPolicyCEPCES/golden/computer,_no_entries,_samba_cache_present |
Updates CEPCES golden. |
internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/unenroll_with_cepces_not_installed |
Adds missing-CEPCES golden. |
internal/policies/certificate/testdata/TestCertAutoenrollScript/golden/unenroll_with_certmonger_not_installed |
Adds missing-certmonger golden. |
internal/policies/certificate/trust.go |
Installs CA trust artifacts. |
internal/policies/certificate/trust_test.go |
Tests trust transactions. |
internal/policies/manager.go |
Integrates certificate manager. |
internal/policies/manager_test.go |
Tests manager integration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
adombeck
left a comment
There was a problem hiding this comment.
I'll wait until the Copilot comments were addressed before reviewing this. Please request a review again when that's done. Thanks!
|
All Copilot comments are addressed, in five commits on top of the branch:
@adombeck ready for your review. |
d6d6d3d to
27cef91
Compare
Certificate autoenrollment so far relied on CEPCES, a Python service that has to be set up and maintained on the Windows side. That setup is easy to get wrong, and CEPCES exists to serve machines that are not domain members - which is never the case for adsys. Enroll natively instead. The machine binds to Active Directory over LDAP using its own Kerberos credentials, discovers the enrollment services, CAs and templates straight from the configuration naming context, and submits CSRs to the CA over MS-ICPR. Nothing beyond a working AD CS deployment is required from the administrator. The backend is selected by the new certificate_enrollment setting. It defaults to cepces so existing installations keep their current behaviour; only an explicit opt-in switches a machine to the native path. The native path owns the material it issues: enrollment state is kept in JSON next to the certificates, CA chains are installed into the system trust store, keys and certificates are renewed as a pair through O_EXCL temporary files, and manager-approval requests are tracked as pending enrollments until the CA issues or denies them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The policy update integration tests could not run unattended anymore. The mock containers resolve the connecting UID through the local passwd and group files only, so a developer whose account comes from LDAP or SSSD was unresolvable inside the container, and the certmonger and CEPCES scenarios shared one golden tree even though the two binaries fail independently. Copy the host NSS databases into the container and append the current user and group when the local files do not already provide them, split the certmonger and CEPCES scenarios into their own goldens, and isolate the dependency PATH so the suite no longer picks up host binaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Describe the certificate_enrollment setting and what each backend requires, so administrators can tell which path a machine is on and what the native one expects from the domain. The setup guide now states the network prerequisites for the LDAP method - StartTLS to the domain controllers and the CA's RPC endpoint - the troubleshooting guide covers the native path's failure modes rather than only certmonger's, and the CEP/CES external links section goes away with the requirement to configure those services. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two eligibility checks disagreed with what Active Directory itself computes, so machines silently enrolled fewer certificates than the domain grants them. Templates carrying CT_FLAG_PEND_ALL_REQUESTS were rejected outright, yet that flag is the ordinary "CA certificate manager approval" setting and the enrollment lifecycle already persists and polls a pending disposition until an operator approves it. Rejecting the flag made the advertised manager-approval support unreachable. An ACE granting GENERIC_ALL was read as granting no control access at all. Windows expands generic rights through the object's generic mapping before the access check, and for directory objects that mapping contains ADS_RIGHT_DS_CONTROL_ACCESS, so a template whose applicable ACE grants (or denies) GenericAll was evaluated the wrong way round. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A machine that had any local CA certificate in the global trust directory could never complete its first native enrollment: the directory is shared with the administrator, but every parseable certificate in it counted as adsys-managed trust, which is precisely the condition that disables the first-enrollment bootstrap. The domain controller certificate then had no way to chain to a trusted root and StartTLS verification failed. Attribute only the artifacts adsys installs, recognized by the on-disk name that installCAChain generates. Unrelated roots still join the verification pool, so an administrator-installed CA that legitimately signs the DC certificate keeps working; it just no longer stands in for the AD CS root that adsys has not installed yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Certificate verification and CA discovery are available to every local caller, and both held the manager and trust lifecycle locks for the whole of their network sequence: one CRL fetch per certificate, up to ten seconds each, or a full LDAP discovery round. Repeatedly asking for them was enough to keep policy application and every other certificate operation waiting. Verification now reads the state and the on-disk material under the locks and releases them before contacting a CRL distribution point, and discovery dials the domain controllers before taking the locks it needs to cross-reference the local state. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Several failures were swallowed on paths that had already committed enrollment state, so a machine could be told everything was fine while the system disagreed. A failing update-ca-certificates was only logged. The certificates and their CA chain are on disk and recorded in the state at that point, but the generated system bundle is stale, so consumers still cannot trust the CA that was just installed - or still trust one that was just removed. The refresh is now part of the reported result of enrollment, unenrollment, renewal and removal. It does not roll back the enrollment: a valid certificate must not be discarded because a bundle refresh failed, and the next refresh retries. Retiring a legacy CEPCES enrollment deleted the Samba cache even when the helper had returned early because certmonger is not installed. That cache is the only record of the legacy certificates, keys and trust store entries, so deleting it stranded them permanently. It is kept instead, and the retire is retried on the next refresh; unenrollment goes through the same helper so it cannot delete the cache behind its back either. WithEnrollmentMethod silently kept the default when handed a value that is neither "ldap" nor "cepces", so a caller asking for a backend could get the other one. Option failures are now collected and returned by New. The trust store refresh is injectable so the tests, which run unprivileged, do not depend on the system command. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The configuration sample and the certificate guides announced that new installations default to the native LDAP backend and documented the adsysctl certificate commands. Neither is true yet: the code default is cepces, the packaging change that writes the ldap default and the management CLI both come later in this series, so a reader following this documentation would set expectations the release does not meet, or run a command that does not exist. Document the code default, and describe how to inspect natively enrolled certificates with what is available today: their layout on disk. The generated daemon CLI reference goes away with it. It is refreshed automatically once merged, so carrying it here only adds unrelated drift - an option documented on main long before this series - to the diff. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The reference is produced by go generate ./cmd/adsysd and is not regenerated anywhere after merge, despite what CONTRIBUTING.md still claims: the automation that used to do it stopped running in 2023. A change adding a flag therefore has to carry the regenerated file itself or the published reference silently omits it. Document --certificate-enrollment, added by this series. The bulk of the diff is the column realignment that the longer flag name forces on every option block. This also picks up --gpo-list-timeout, which landed on main without a refresh and would otherwise stay missing until something else happened to regenerate the file.
be18dd8 to
16e6149
Compare
| # Native Go implementation (LDAP/RPC) — default for new installations | ||
| certificate_enrollment: ldap |
There was a problem hiding this comment.
Is it relevant information for users that the implementation is native Go?
| # Legacy Python/CEPCES implementation — default for existing installations | ||
| # certificate_enrollment: cepces |
There was a problem hiding this comment.
Likewise, I'm skeptical if it's relevant that this is implemented in Python. Making clear that it's not the recommended method and mainly there for backwards compatibility ("legacy") makes sense to me though.
Certificate enrollment has been a point of struggle for adsys' users for a while now. Although it works, configuring CEPCES servers on Windows is not easy and comes with many pitfalls that can block the enrollment process. Also, CEPCES was designed to allow enrollment for machines outside of the domain, which is not the case for adsys.
This adds a native Go enrollment backend that talks to AD CS directly — LDAP for discovery, MS-ICPR over RPC for issuance — so autoenrollment needs no setup beyond the AD CS service itself. The legacy CEPCES path is kept intact and selectable.
UDENG-11047
What this contains
The certificate engine: everything under
internal/policies/certificate/, plus the configuration plumbing that selects a backend. No new user-facing commands — those come in the next PR.AutoEnrollright.certificate_enrollmentsetting (ldap|cepces), validated at every layer.The code default stays
cepces, so this is behaviourally inert for every existing installation. Fresh installs opt intoldapin the packaging PR at the end of the stack.Security notes
O_EXCLtemp files and renamed. Reconciliation is crash-safe, and a failed renewal keeps the still-valid certificate rather than letting orphan cleanup delete it.ADSYS_TESTS_WITHOUT_KERBEROSis gated behindtesting.Testing()and cannot take effect in production builds.Notes for reviewers
CertAutoEnrollScriptandadsysctl policy cert-autoenroll-scriptare unchanged — both files are byte-identical tomain.internal/consts→ldap.go/gssapi.go→access.go/template.go→enroll.go→state.go/lifecycle.go/pending.go→certificate.go.UDENG-11047