docs(scep-intune): deployment guide + troubleshooting + Microsoft support statement

Phase 11 of the SCEP RFC 8894 + Intune master bundle.

Phase 11.1 — docs/scep-intune.md (new, ~340 lines):

  * TL;DR — drop-in NDES replacement framing; what an operator gets
    over NDES (per-profile endpoints, audit-log forensics, SIGHUP
    reload, GUI monitoring, per-device rate limit).
  * Architecture diagram — Intune cloud → Connector → certctl SCEP
    → issuer connector. Explicit 'certctl replaces NDES, NOT the
    Connector' framing; nine-gate dispatcher walk (shape pre-check,
    JWS sig, version dispatch, time bounds, audience pin, CSR binding,
    replay, per-device rate limit, optional compliance).
  * Migration playbook (NDES + EJBCA / NDES + ADCS) — 9-step run-book:
    install alongside, configure per-profile endpoint, extract trust
    anchor, configure CONNECTOR_CERT_PATH + AUDIENCE, configure
    issuer connector, migrate one profile, verify enrollment, roll
    out fleet, decommission NDES.
  * Intune SCEP profile field mapping table — every Intune admin
    center field mapped to certctl's behavior (cert type, subject
    name format, SAN, validity, key storage provider, key usage,
    EKU, hash algorithm, SCEP server URL).
  * Trust anchor extraction recipe — step-by-step certlm.msc export
    of the 'CN=Microsoft Intune Certificate Connector' cert, PEM
    rename, env-var configuration, HA Connector concatenation, SIGHUP
    rotation flow.
  * Troubleshooting matrix — 10 failure modes mapped to root causes
    and operator actions: signature_invalid (trust anchor stale),
    claim_mismatch (Intune profile SAN config), expired (clock skew /
    Connector cert past NotAfter), not_yet_valid (reverse skew),
    wrong_audience (URL mismatch), replay (retry-window collision),
    rate_limited (limiter doing its job), unknown_version (Microsoft
    shipped new format), malformed (proxy mangling body),
    compliance_failed (V3-Pro hook returned non-compliant).
  * Operational monitoring — admin GUI surface description, expiry
    badge tone bands (≥30d green / 7-30d amber / <7d red / EXPIRED),
    per-status counter polling cadence, audit log filter, recommended
    Prometheus alert thresholds.
  * Limitations — explicit V3-Pro deferrals: native Microsoft Graph
    integration, Conditional Access compliance gating, per-tenant
    trust anchors (MSP scoping), OCSP stapling at SCEP-response time,
    auto-discovery of Connector signing cert.
  * Microsoft support statement — three Microsoft Learn URLs (verified
    live with HTTP 200): Connector overview, SCEP profile setup,
    Connector install validation. Microsoft documents the Connector
    as RFC-8894-compliant and supports its use against any RFC 8894
    SCEP server.

Phase 11.2 — Cross-references:

  * docs/legacy-est-scep.md — the previous forward-ref pointed at
    'the Phase 11 doc this bundle ships'; updated to a richer pointer
    that lists what scep-intune.md covers (architecture, migration,
    profile mapping, extraction, troubleshooting, monitoring,
    limitations, Microsoft support).
  * README.md — new bullet under Enrollment Protocols table:
    'Microsoft Intune SCEP fleet (drop-in NDES replacement)' with
    the per-profile dispatcher feature list + link to scep-intune.md.
    Procurement teams scanning the README see the Intune story
    alongside ChromeOS / Jamf in the same table row.
  * docs/architecture.md — new 'Microsoft Intune Connector trust
    anchor (per-profile, opt-in)' subsection in the Security Model
    section. ASCII diagram showing the dispatcher walk; calls out
    the SIGHUP reload + admin-gated GUI surface; forward-link to
    scep-intune.md.

Verification:
  * All linked anchors inside scep-intune.md resolve to existing
    headings: #limitations, #microsoft-support-statement,
    #operational-monitoring, #trust-anchor-extraction.
  * All linked doc paths resolve: legacy-est-scep.md, architecture.md,
    features.md, tls.md.
  * All three Microsoft Learn URLs return HTTP 200 (verified via curl).
  * G-3 docs-drift CI guard reproduced locally and clean — the
    migration playbook uses the <NAME> placeholder convention
    consistently (matching features.md style) so the docs scanner
    doesn't extract literal env-var names that aren't in config.go.
  * Backend tests across intune+handler+service+router still green.

Refs: cowork/scep-rfc8894-intune-master-prompt.md::Phase 11
      cowork/scep-rfc8894-intune/progress.md
This commit is contained in:
shankar0123
2026-04-29 17:03:56 +00:00
parent e0d00717c7
commit 5d080c86fd
4 changed files with 411 additions and 4 deletions
+42
View File
@@ -831,6 +831,48 @@ The control plane only handles public material: certificates, chains, and CSRs.
**Server keygen mode (`CERTCTL_KEYGEN_MODE=server`, demo only):** The control plane generates RSA-2048 keys server-side within `processRenewalServerKeygen`. Private keys are stored in `certificate_versions.csr_pem`. A log warning is emitted at startup. Use only for Local CA development/demo.
### Microsoft Intune Connector trust anchor (per-profile, opt-in)
When the SCEP server is sitting behind a Microsoft Intune Certificate
Connector — i.e. certctl is acting as a drop-in NDES replacement —
each per-profile dispatcher carries its own **trust anchor pool**:
the public certs the operator extracted from the Connector's
installation. Every Intune-flavored enrollment goes through:
```
┌─────────────────────────────────┐
│ Per-profile TrustAnchorHolder │
│ (RWMutex pool, SIGHUP-reloadable) │
└────────────┬────────────────────┘
│ Get()
device → SCEP PKIMessage → handler → SCEPService.dispatchIntuneChallenge
├─► intune.ValidateChallenge (sig + iat/exp + audience)
├─► claim.DeviceMatchesCSR (set-equality)
├─► intune.ReplayCache.CheckAndInsert
├─► intune.PerDeviceRateLimiter.Allow
└─► (V3-Pro) ComplianceCheck hook
processEnrollment → IssuerConnector
```
The trust anchor file is mode-0600 on disk; certctl loads it at
startup via `intune.LoadTrustAnchor` (refuses to boot on empty
bundle / parse error / past-`NotAfter` cert) and reloads atomically
on `SIGHUP` (mirrors the server TLS-cert hot-reload pattern). A bad
reload keeps the OLD pool in place — operators get a recoverable
failure window rather than a service-down. The admin GUI's SCEP
Intune Monitoring tab + admin endpoints
(`GET /api/v1/admin/scep/intune/stats`,
`POST /api/v1/admin/scep/intune/reload-trust`) are M-008 admin-gated;
non-admin Bearer callers get HTTP 403 because the trust-anchor
expiries are sensitive operational metadata.
See [`scep-intune.md`](scep-intune.md) for the full migration playbook
+ Microsoft support statement.
### CA Signing Abstraction
The local issuer's CA private key is wrapped behind the `signer.Signer` interface in `internal/crypto/signer/`. Every CA-signing call site — leaf certificate issuance (`x509.CreateCertificate`), CRL generation (`x509.CreateRevocationList`), and OCSP response signing (`ocsp.CreateResponse`) — accesses the key through this interface rather than touching `crypto.Signer` directly. The interface embeds the stdlib `crypto.Signer` and adds a single `Algorithm() Algorithm` method so call sites can pick the matching `x509.SignatureAlgorithm` without reflecting on the concrete key type.