Skip to content

Add renewal marker to Fleet-generated Conditional Access profile so auto-renewal activates by default (sub-task of #40639) #45580

@mostlikelee

Description

@mostlikelee

Part of #40639. Updated 2026-05-15 to reflect Decision 2.6 scope reversal.

Background

The Fleet-generated Conditional Access SCEP profile (template at server/service/conditional_access_idp.go:23) currently has a Subject with CN only, no OU and no renewal marker:

<key>Subject</key>
<array>
    <array>
        <array>
            <string>CN</string>
            <string>{{.CertificateCN}}</string>
        </array>
    </array>
</array>

Scope change — why this is no longer a blocker

The original framing of this issue (pre-2026-05-15) was that PR #45364's validator would reject the Fleet-generated profile because it lacked the marker, breaking the published Conditional Access guide. That validator has since been reverted (Decision 2.6 scope reversal — marker is now opt-in, not required for upload). So the rejection failure mode is gone — customers following the guide today won't hit an upload error.

However, the underlying gap remains: even without rejection, the Conditional Access cert won't auto-renew because no marker means no host_mdm_managed_certificates row gets created. The published guide says "Automatic renewal for this certificate is coming soon." To deliver that promise out of the box — without forcing every Conditional Access customer to manually opt in by editing their custom-OS-settings profile — Fleet should include the marker in the generated template.

Why default-on for Conditional Access specifically

Conditional Access is the cleanest opt-in default-on candidate:

  1. Fleet owns the entire CA. Fleet's own SCEP CA mints the cert (ee/server/service/condaccess/config.go:33-62). OU preservation is fully under Fleet's control — no external CA cooperation risk.
  2. Fleet generates the profile. Adding the marker is a one-line template change; customers never have to touch it.
  3. The customer outcome maps 1:1 to the marker. Every Conditional Access customer wants their cert to renew automatically — there's no "opt-out" use case for this specific feature.
  4. The published guide already promises this. The "coming soon" link points at Automatically re-push profile for certificates not proxied through Fleet #40639; delivering auto-renewal requires the marker to be present.

Proposed fix

Update the SCEP payload's Subject in server/service/conditional_access_idp.go template to include an OU containing \$FLEET_VAR_CERTIFICATE_RENEWAL_ID:

<key>Subject</key>
<array>
    <array>
        <array>
            <string>CN</string>
            <string>{{.CertificateCN}}</string>
        </array>
    </array>
    <array>
        <array>
            <string>OU</string>
            <string>\$FLEET_VAR_CERTIFICATE_RENEWAL_ID</string>
        </array>
    </array>
</array>

Fleet's profile-delivery substitution rewrites the variable to fleet-<profile_uuid> before sending to the device. Fleet's own Conditional Access SCEP CA mints the cert (so OU preservation is guaranteed, unlike external-CA scenarios). Ingestion → matcher → INSERT path → managed-cert row → renewal cron all activate as designed.

Acceptance criteria

  • Template at server/service/conditional_access_idp.go Subject includes an OU containing \$FLEET_VAR_CERTIFICATE_RENEWAL_ID.
  • Verify Fleet's Conditional Access SCEP CA preserves OU in the issued cert (it controls the entire issuance, so this should be straightforward — but worth a quick verification end-to-end).
  • Add an end-to-end integration test: deploy the generated Conditional Access profile to a host, simulate cert ingestion, verify the managed-cert row materializes with the expected profile_uuid.
  • Update articles/okta-conditional-access-integration.md to remove the "Automatic renewal for this certificate is coming soon" language (the promise is now delivered). Mention that the old certificate cleanup script remains relevant.
  • Customers running pre-4.86 Conditional Access profiles need to re-download the User scope profile from Settings → Integrations → Conditional access → Okta and re-deploy it once. Document this as a one-time opt-in step in the upgrade notes (or the guide itself).

References

Metadata

Metadata

Assignees

Labels

#g-security-complianceSecurity & Compliance product group~sub-taskA technical sub-task that is part of a story. (Not QA'd. Not estimated.)

Type

No type

Projects

Status

🦤 ‎In review

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions