From 7e2cf0aa9a7cc96fb7e2b59f7bfbb06b1d505247 Mon Sep 17 00:00:00 2001 From: Irena Reedy <205901210+irenareedy@users.noreply.github.com> Date: Fri, 30 Jan 2026 08:41:42 -0800 Subject: [PATCH] =?UTF-8?q?Create=20enable-okta-verify-on-windows-using-a-?= =?UTF-8?q?scep-configuration-profi=E2=80=A6=20(#38716)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …le.md Adam Baali's article --------- Co-authored-by: Adam Baali <45665341+AdamBaali@users.noreply.github.com> Co-authored-by: Brock Walters <153771548+nonpunctual@users.noreply.github.com> --- ...dows-using-a-scep-configuration-profile.md | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 articles/enable-okta-verify-on-windows-using-a-scep-configuration-profile.md diff --git a/articles/enable-okta-verify-on-windows-using-a-scep-configuration-profile.md b/articles/enable-okta-verify-on-windows-using-a-scep-configuration-profile.md new file mode 100644 index 0000000000..d8acd329c8 --- /dev/null +++ b/articles/enable-okta-verify-on-windows-using-a-scep-configuration-profile.md @@ -0,0 +1,223 @@ +# Enable Okta Verify on Windows using a SCEP configuration profile + +## Introduction + +This guide explains how to enable [Okta Verify](https://help.okta.com/en-us/content/topics/mobile/okta-verify-overview.htm) on Windows using a SCEP client certificate delivered by the Windows **ClientCertificateInstall** CSP and then applied using an **Exec** command. This pattern is useful when your MDM payload cannot send **Add or Replace** nodes together with an **Exec** in one transaction. + +You will deploy the SCEP profile first, then call **Enroll** via Exec to request the client certificate. + +**Files** +* [Profile XML](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/configuration-profiles/install%20Okta%20attestation%20certificate%20-%20%5BBundle%5D.xml) +* [Powershell script](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/scripts/trigger%20scep%20enrollment.ps1) + +--- + +## Order at a glance + +1. Get your CA **thumbprint**, choose **{yourCertName}**, and locate your SCEP **URL** and **Challenge**. +2. Create Fleet **secrets** for URL, Challenge, CA thumbprint, and API token. +3. Use the Fleet repo XML CSP profile and replace only the required placeholders. +4. Deploy the profile to devices. +5. Update the **Exec** script to use the same `{yourCertName}` and your secrets, then run it. +6. Verify the certificate is installed. +7. Plan and automate **renewal**. + +--- + +## Prerequisites + +* Windows devices enrolled to Fleet MDM +* Okta SCEP endpoint with a static challenge +* Root CA certificate thumbprint for the SCEP issuing CA +* Fleet API token stored as a secret +* Optional GitOps workflow if you manage Fleet configuration as code + +--- + +## Step 1. Collect your values + +### 1.1 Get the CA thumbprint + +**Windows PowerShell** +```powershell +Get-FileHash -Path "C:\Path\To\ca.cer" -Algorithm SHA256 | Select-Object -ExpandProperty Hash +``` + +**macOS or Linux** +```bash +openssl x509 -in ~/Downloads/ca.cer -noout -fingerprint -sha256 +# Output looks like: +# SHA256 Fingerprint=E2:18:D7:A7:B0:DF:ED:79:B2:05:73:BA:79:CB:14:B1:FE:EA:D2:7B +# Remove the colons: +# E218D7A7B0DFED79B20573BA79CB14B1FEEAD27B +``` + +Use the hex string without colons or spaces in the secret you will create below. + +### 1.2 Choose your SCEP node name + +Pick a simple value for `{yourCertName}`, for example `OKTA` or `OKTAVERIFY`. You will use this exact value: +* in the XML profile path `.../SCEP/{yourCertName}/Install/...` +* in the Exec path `.../SCEP/{yourCertName}/Install/Enroll` + +### 1.3 Get your SCEP URL and Challenge + +* `{yourScepUrl}` is your Okta SCEP endpoint. +* `{yourScepChallenge}` is your static SCEP challenge. This profile expects **plain text**. Avoid special characters that can break XML or transport. Recommended: letters, numbers, underscore. If your challenge contains characters such as `! @ # $ % ^ & * ( )`, rotate to a simpler value. + +**Quick checklist** +* {yourCertName} chosen +* {yourScepUrl} confirmed +* {yourScepChallenge} validated (plain text, simple characters) +* {yourScepCAThumbprint} ready (no colons, no spaces) + +--- + +## Step 2. Create Fleet secrets + +Follow Fleet’s guide: https://fleetdm.com/guides/secrets-in-scripts-and-configuration-profiles + +Create these secrets in Fleet (Controls → Variables) or via GitOps: + +| Secret name | Value you collected | +|---|---| +| `FLEET_SECRET_OKTA_SCEP_URL` | `{yourScepUrl}` | +| `FLEET_SECRET_OKTA_SCEP_CHALLENGE` | `{yourScepChallenge}` (plain text, simple characters) | +| `FLEET_SECRET_OKTA_CA_THUMBPRINT` | SHA256 thumbprint with no colons, no spaces +| `FLEET_SECRET_API` | Fleet API token used by the Exec script | + +Optional convenience secret: +* `FLEET_SECRET_OKTA_CERT_NAME` set to `{yourCertName}` + +**Security notes** +* Fleet does not hide the secret in script results. Don't print/echo your secrets to the console output. + +--- + +## Step 3. Use Fleet’s XML CSP profile + +Source file in the Fleet repo: +``` +docs/solutions/Windows/configuration-profiles/install Okta attestation certificate - [Bundle].xml +``` + +Only change the following placeholders: + +* `{yourCertName}` set to the SCEP node name you chose in Step 1.2 +* `{yourScepUrl}` replaced with `$FLEET_SECRET_OKTA_SCEP_URL` +* `{yourScepChallenge}` replaced with `$FLEET_SECRET_OKTA_SCEP_CHALLENGE` (plain text, simple characters) +* `{yourScepCAThumbprint}` replaced with `$FLEET_SECRET_OKTA_CA_THUMBPRINT` (no colons, no spaces) + +**Important** +Use the same `{yourCertName}` in both the profile path and the Exec path. If they differ, the Exec will 404. + +### Replace just these lines in the profile + +```xml + + + + ./Device/Vendor/MSFT/ClientCertificateInstall/SCEP/{yourCertName}/Install/ServerURL + + chr + $FLEET_SECRET_OKTA_SCEP_URL + + + + + + ./Device/Vendor/MSFT/ClientCertificateInstall/SCEP/{yourCertName}/Install/Challenge + + chr + $FLEET_SECRET_OKTA_SCEP_CHALLENGE + + + + + + ./Device/Vendor/MSFT/ClientCertificateInstall/SCEP/{yourCertName}/Install/CAThumbprint + + chr + $FLEET_SECRET_OKTA_CA_THUMBPRINT + +``` + +Keep the other defaults from the file (KeyLength 2048, KeyUsage 160, HashAlgorithm `SHA-1`, SubjectName `CN=$FLEET_VAR_HOST_UUID managementAttestation`, EKUMapping, RetryCount, RetryDelay). + +Deploy the profile to your Windows hosts using Fleet. + +--- + +## Step 4. Update the Exec script and run Enroll + +Script location in repo: +`docs/solutions/Windows/scripts/trigger-scep-enrollment.ps1` + +Your Exec must target the same `{yourCertName}` as in the profile. Example path: +``` +./Device/Vendor/MSFT/ClientCertificateInstall/SCEP/{yourCertName}/Install/Enroll +``` + +Update your PowerShell script to read the API token from the secret, set your node name, and build the correct LocURI. + +```powershell +# ----- USER SETTINGS ----- +# Add your secrets in Fleet (Controls > Variables) or via GitOps. +# The variable named "API" becomes FLEET_SECRET_API +# Full guidance: https://fleetdm.com/guides/secrets-in-scripts-and-configuration-profiles + +$NODE_NAME = "OKTA" # must match {yourCertName} in the XML +$FLEET_API = "$FLEET_SECRET_API" # injected by Fleet + +$locUri = "./Device/Vendor/MSFT/ClientCertificateInstall/SCEP/$NODE_NAME/Install/Enroll" +# ...construct and send the Exec command body referencing $locUri... +``` + +Run the script from Fleet so secrets inject automatically. + +--- + +## Step 5. Verify enrollment + +**PowerShell** +```powershell +Get-ChildItem Cert:\LocalMachine\My | + Where-Object { $_.Subject -like "*managementAttestation*" } | + Format-List Subject, Thumbprint, NotAfter +``` + +**GUI** +* Open `certlm.msc` +* Personal > Certificates +* Confirm a certificate whose Subject contains `managementAttestation` + +--- + +## Step 6. Renewal + +* Automated workflow. Use a Fleet query to find certificates expiring within 30 days and trigger the Exec command for those hosts. + +Find certs expiring within 30 days: +```TODO! +``` + +--- + +## Troubleshooting + +* Exec returns 404: node name mismatch. Ensure `{yourCertName}` in XML equals `$NODE_NAME` in the script. +* Enrollment fails immediately: check `ServerURL`, `CAThumbprint` format, and that the device can reach the SCEP URL. +* Challenge rejected: try a simpler plain text challenge, or base64 encode and update the XML ``. +* Nothing in `Cert:\LocalMachine\My`: review Device Management logs + ```powershell + Get-WinEvent -LogName Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin -MaxEvents 50 + ``` + +--- + + + + + + +