From 09b6e94d7adde68f40e19a5ce606723c2cbf13e3 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 6 Jul 2026 19:27:53 +0200 Subject: [PATCH 01/16] Add Google Workspace WIF integration docs --- .../connect-google-workspace-to-smallstep.mdx | 98 +++++++++++++++++-- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index 1d9b4773..5c012524 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -5,7 +5,7 @@ html_title: Integrate Google Workspace with Smallstep Tutorial description: Integrate Google Workspace with Smallstep for Chromebook device security. Complete guide for enforcing device trust in ChromeOS environments. --- -Smallstep can integrate with Google Workspace to keep your ChromeOS device inventory in sync. +Smallstep can integrate with Google Workspace to keep your ChromeOS device inventory in sync and manage credentials for ChromeOS devices. # Prerequisites @@ -34,36 +34,77 @@ Your Google Cloud project must have the Admin SDK API enabled. By default, it is 5. Choose **Done** 6. Open the details for the Service Account you just created 7. Copy the **Unique ID** (numeric) and the **Email** shown on the details tab; you’ll need them later -8. Visit the **Keys** tab, and choose **Add key**, then **Create new key** -9. Choose **Create** to create a JSON key -A file containing the service account key will be downloaded. Keep this safe and secure! +### 2. Setup Workload Identity Federation -### 2. Grant device directory API permissions +The Smallstep platform authenticates to your Google Workspace through Workspace Identity Federation for Google Kubernetes Engine. + +1. In Google Cloud, visit [IAM & Admin → Workload Identity Federation](https://console.cloud.google.com/iam-admin/workload-identity-pools) +2. Choose **Create pool** +3. Set a name, e.g. "Smallstep Google Workspace Sync Pool" +4. Optionally, provide a **Description** for the pool +5. Click **Continue** +6. Select **OpenID Connect (OIDC)** as the provider +7. Set a name, e.g. "Smallstep Google Workspace Sync" +8. Set the issuer URL to **https://container.googleapis.com/v1/projects/prod-us-central1-e5bd/locations/us-central1/clusters/primary** +9. Keep **Default audience** checked +10. Click **Continue** +11. For the **google.subject** attribute, set **assertion.sub** +12. Click **Add mapping**, and set **attribute.k8s_sa** to **assertion.kubernetes.io.serviceaccount.name** +13. Click **Save** + +### 3. Grant Access to the Service Account + +1. Click **Grant access** +2. Select **Grant access using service account impersonation** +3. Select the **Service account** you created earlier from the dropdown +4. Select **k8s_sa** as the attribute +5. Set **system:serviceaccount:default:inventory** as the value for the attribute +6. Click **Save** +7. When the modal appears, you can **Dismiss** it + +### 4. Grant device directory API permissions 1. In Google Admin, visit [Security → Access and data control → API controls](https://admin.google.com/ac/owl) 2. Under Domain wide delegation, select **Manage Domain Wide Delegation** 3. In the **API Clients** table, select **Add new** 1. Enter the **Unique ID** of the service account from Step 1 - 2. For the **OAuth Scopes**, enter the following scope: + 2. For the **OAuth Scopes**, enter the following scopes: ``` https://www.googleapis.com/auth/admin.directory.device.chromeos + https://www.googleapis.com/auth/verifiedaccess ``` 3. Choose **Authorize** -### 3. Add Google Workspace to Smallstep +### 5. Create and Assign Custom Admin Role to Service Account + +1. In Google Admin, visit [Account → Admin roles](https://admin.google.com/ac/list/roles) +2. Click **Create new role** +3. Give it a descriptive name, e.g. **Google Workspace Sync** +4. Enable the **Manage ChromeOS Devices** privilege (incl. all subitems) +5. Click **Continue** +6. Click **Create role** +7. Click the newly created role +8. Click **Admins assigned** +9. Click **Assign service accounts** +10. Enter the principal of the service account created earlier +11. Click **Assign role** + +### 6. Add Google Workspace to Smallstep In Smallstep, visit [Settings → Device Management](https://smallstep.com/app/?next=/settings/devices). Configure a new Google Workspace Integration with the following values: - The **Customer ID** of your Google Workspace tenant. The Customer ID is a short alphanumeric string. It can be obtained from the Google Workspace Admin [Account Settings](https://admin.google.com/ac/accountsettings/profile) page -- The **Service Account JSON key** you downloaded earlier -- An email address of a user in your Google Workspace directory with admin permissions +- The **Project ID** of the GCP project your service account was created in +- The **workload identity pool** +- The **workload identity provider** +- The service account **principal** -### 4. Add Smallstep certificates to Google Workspace +### 7. Add Smallstep certificates to Google Workspace After saving the Google Workspace connection, you will see settings for your integration. @@ -85,6 +126,43 @@ After saving the Google Workspace connection, you will see settings for your int - Choose **Add** 5. Repeat Step 4 for each of the certificates you downloaded +### 8. Verified Access Mode Configuration + +1. In Google Workspace, visit [Devices → Chrome → Settings](https://admin.google.com/ac/chrome/settings/device). +2. Select **Device settings** +3. Click **Verified mode** +4. Ensure the correct **Organizational Unit** is selected for scoping the configuration +4. Under Configuration, select **Require verified mode boot for verified access** +5. Set the email address of the GCP service account in the **Services with full access** field +6. Click Save + +### 9. ChromeOS Extension Configuration + +1. In Google Workspace, visit [Devices → Chrome → Apps & extension](https://admin.google.com/ac/chrome/apps). +2. Click **Users & browsers** +3. Ensure the proper **Organizational Unit** is selected for scoping the configuration +4. Click the **+** icon on the bottom right +5. Click **Add Chrome app or extension by ID** +6. Set the **Extension ID** to **icjpnolkgdnfgpccpkdlipalcmalkndl** +7. In the dropdown, choose **From a custom URL**, and set it to **https://packages.smallstep.com/chromeos/latest/update.xml** +8. Click **Save** +9. Click the newly created extension to edit it +10. Select **Force install + pin** as the **Installation policy** +11. Under **Certificate management**, enable **allow access to keys** and **Allow enterprise challenge** +12. Under **Policy for extensions**, add the following JSON, replacing **>** with your Smallstep team slug: + +```{ + "team": { + "Value": "" + } +} +``` +13. Click **Save** in the top right corner +14. Scroll down in the side panel details, and ensure the installation URL is set to ... +15. Set the **Update URL** to **Installation URL (see above)** +16. Click **Save** + + ### Confirmation Within a few minutes, you should see all of your ChromeOS devices in Smallstep's [Devices](https://smallstep.com/app/?next=/devices/all) tab. From 28081f9f8d54d10fbba691ff05b2cb5e69fe625d Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 27 Jul 2026 09:30:31 +0200 Subject: [PATCH 02/16] Use `sts.googleapis.com` as audience in Google Workspace WIF Also specify the numeric GCP project ID to be used. --- tutorials/connect-google-workspace-to-smallstep.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index 5c012524..38ece000 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -47,7 +47,7 @@ The Smallstep platform authenticates to your Google Workspace through Workspace 6. Select **OpenID Connect (OIDC)** as the provider 7. Set a name, e.g. "Smallstep Google Workspace Sync" 8. Set the issuer URL to **https://container.googleapis.com/v1/projects/prod-us-central1-e5bd/locations/us-central1/clusters/primary** -9. Keep **Default audience** checked +9. Set **Allowed audiences** to `sts.googleapis.com` 10. Click **Continue** 11. For the **google.subject** attribute, set **assertion.sub** 12. Click **Add mapping**, and set **attribute.k8s_sa** to **assertion.kubernetes.io.serviceaccount.name** @@ -99,7 +99,7 @@ In Smallstep, visit [Settings → Device Management](https://smallstep.com/app/? Configure a new Google Workspace Integration with the following values: - The **Customer ID** of your Google Workspace tenant. The Customer ID is a short alphanumeric string. It can be obtained from the Google Workspace Admin [Account Settings](https://admin.google.com/ac/accountsettings/profile) page -- The **Project ID** of the GCP project your service account was created in +- The numeric **Project ID** of the GCP project your service account was created in - The **workload identity pool** - The **workload identity provider** - The service account **principal** From 0fbeccab74e1e234b91f473500c92cfb8d738a1c Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 27 Jul 2026 09:43:47 +0200 Subject: [PATCH 03/16] Ignore `https://container.googleapis.com` in link checker --- .github/mdl.config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/mdl.config.json b/.github/mdl.config.json index 001dc72c..bcd71a20 100644 --- a/.github/mdl.config.json +++ b/.github/mdl.config.json @@ -71,6 +71,9 @@ }, { "pattern": "^https://datatracker.ietf.org" + }, + { + "pattern": "^https://container.googleapis.com/*" } ], "replacementPatterns": [ From 4586a4ae229eb34f4cc3cffefc314bca78247cd5 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Wed, 29 Jul 2026 15:59:00 +0200 Subject: [PATCH 04/16] Add Verified Access API to prerequisites --- tutorials/connect-google-workspace-to-smallstep.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index 38ece000..aa640aa2 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -19,11 +19,12 @@ You will need: In Google Cloud Console, select a project you will use for Smallstep. This can be any project, as long as you can grant domain-wide delegation to the client in a future step. -Your Google Cloud project must have the Admin SDK API enabled. By default, it is disabled. +Your Google Cloud project must have the Admin SDK and Chrome Verified Access APIs enabled. By default, they're disabled. -### 0. Enable admin SDK API +### 0. Enable APIs 1. Go to [Admin SDK API](https://console.cloud.google.com/apis/api/admin.googleapis.com) for your project, and choose **Enable API** +2. Go to [Chrome Verified Access API](https://console.cloud.google.com/marketplace/product/google/verifiedaccess.googleapis.com) for your project, and choose **Enable API** ### 1. Create a service account for Smallstep From a61822dba0c9911a8047b9c95d07289884bf46b1 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Wed, 29 Jul 2026 16:40:55 +0200 Subject: [PATCH 05/16] Fix JSON markup --- tutorials/connect-google-workspace-to-smallstep.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index aa640aa2..cb93f76c 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -150,9 +150,10 @@ After saving the Google Workspace connection, you will see settings for your int 9. Click the newly created extension to edit it 10. Select **Force install + pin** as the **Installation policy** 11. Under **Certificate management**, enable **allow access to keys** and **Allow enterprise challenge** -12. Under **Policy for extensions**, add the following JSON, replacing **>** with your Smallstep team slug: +12. Under **Policy for extensions**, add the following JSON, replacing with your Smallstep team slug: -```{ +``` +{ "team": { "Value": "" } From 3fbdd0531c93618160458011b4717fc9f73d546f Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 30 Jul 2026 18:30:21 +0200 Subject: [PATCH 06/16] Ignore `../verifiedaccess.googleapis.com` in URL checker --- .github/mdl.config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/mdl.config.json b/.github/mdl.config.json index bcd71a20..bb9ced36 100644 --- a/.github/mdl.config.json +++ b/.github/mdl.config.json @@ -74,6 +74,9 @@ }, { "pattern": "^https://container.googleapis.com/*" + }, + { + "pattern": "^https://console.cloud.google.com/marketplace/product/google/verifiedaccess.googleapis.com" } ], "replacementPatterns": [ From 68fa44ab106dcf31400deec843c6f08bdee3ad96 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 30 Jul 2026 18:47:57 +0200 Subject: [PATCH 07/16] Update `k8s_sa` attribute --- tutorials/connect-google-workspace-to-smallstep.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index cb93f76c..ba6b15a3 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -60,7 +60,7 @@ The Smallstep platform authenticates to your Google Workspace through Workspace 2. Select **Grant access using service account impersonation** 3. Select the **Service account** you created earlier from the dropdown 4. Select **k8s_sa** as the attribute -5. Set **system:serviceaccount:default:inventory** as the value for the attribute +5. Set **system:serviceaccount:prod:inventory** as the value for the attribute 6. Click **Save** 7. When the modal appears, you can **Dismiss** it From 28296ea11157dec3e43a47406f8a2af87905c783 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:07:43 -0500 Subject: [PATCH 08/16] Add ChromeOS device identity certificates tutorial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebased onto herman/chromeos-wif — drops the Verified Access Mode and extension deployment steps that PR previously added, since that PR now covers the same ground as part of its Workload Identity Federation rewrite of the Google Workspace connection flow. --- manifest.json | 4 + .../chromeos-device-identity-certificates.mdx | 105 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 tutorials/chromeos-device-identity-certificates.mdx diff --git a/manifest.json b/manifest.json index 394c2c8c..b3582087 100644 --- a/manifest.json +++ b/manifest.json @@ -93,6 +93,10 @@ "title": "Configure Browser Certificates", "path": "/tutorials/browser-certificate-setup-guide.mdx" }, + { + "title": "Configure ChromeOS Device Identity Certificates", + "path": "/tutorials/chromeos-device-identity-certificates.mdx" + }, { "title": "Configure Enterprise Relay", "path": "/tutorials/configure-enterprise-relay.mdx" diff --git a/tutorials/chromeos-device-identity-certificates.mdx b/tutorials/chromeos-device-identity-certificates.mdx new file mode 100644 index 00000000..d61d65f3 --- /dev/null +++ b/tutorials/chromeos-device-identity-certificates.mdx @@ -0,0 +1,105 @@ +--- +updated_at: July 31, 2026 +title: Configure ChromeOS Device Identity Certificates +html_title: Configure ChromeOS Device Identity Certificates for mTLS | Smallstep +description: Issue mTLS-capable device identity certificates to ChromeOS devices enrolled in Google Workspace, for use in Wi-Fi, VPN, or internal application authentication. +--- + +Smallstep issues two different kinds of certificate to a ChromeOS device enrolled through [Google Workspace](./connect-google-workspace-to-smallstep.mdx): a short-lived **attestation certificate**, issued automatically, and a longer-lived **device identity certificate**, which is what you actually use for mTLS — Wi-Fi (802.1X), VPN, or authenticating to internal applications. + +This guide covers issuing that device identity certificate. It's a prerequisite for [ChromeOS Wi-Fi Enrollment](./protect-wireless-networks.mdx#chromeos-with-google-workspace-acme-device-attestation) and for any other mTLS use case involving ChromeOS devices. + +# Prerequisites + +- A completed [Connect Google Workspace to Smallstep](./connect-google-workspace-to-smallstep.mdx) integration, with devices syncing into Smallstep +- The Smallstep ChromeOS extension deployed to your target Organizational Unit (covered in that same guide) + +# Attestation certificate vs. device identity certificate + +A freshly enrolled ChromeOS device receives only the attestation certificate. It cannot be used for mTLS. Until you complete the steps below, the device will not have a usable identity certificate, even though it will appear fully enrolled and "high assurance" in both the Smallstep dashboard and the Admin Console. + +| | Attestation certificate | Device identity certificate | +|---|---|---| +| Issued by | Team's Intermediate CA | Devices (or Accounts) Intermediate CA | +| Lifetime | 24 hours | 30 days | +| Subject alternative name | `urn:ak:sha256:…` (attestation key) | `urn:smallstep:device:permanent-identifier:` | +| Purpose | Proves genuine hardware after Chrome Verified Access; used as the credential in the ACME Device Attestation exchange | The credential presented for mTLS | +| Available from Certificate Manager? | No — not published to customers | Yes | + + +
+Only the device identity certificate can be used for mTLS. If a device presents only the attestation certificate to an mTLS endpoint, the connection will fail — see Troubleshooting below. +
+
+ +# Step-by-step instructions + +### 1. Choose an issuing authority + +The device identity certificate can be issued from either of two authorities in Certificate Manager: + +- **Devices** — binds the certificate to the device itself (subject is the hardware serial number). Use this for device-level authentication such as Wi-Fi. +- **Accounts** — binds the certificate to the Google Workspace user currently signed in to the device (subject is the user's email). Use this if you need to authenticate the user rather than the device. + +Both authorities support ACME Device Attestation, so the enrollment mechanics in the steps below are identical either way — only the resulting certificate's identity differs. + +### 2. Distribute the authority's trust root to Google Admin + +This step must happen **before** step 3, not after. Each authority's ACME directory is served over TLS using a certificate signed by that authority's own private root. If the Chromebook doesn't already trust that root, it cannot reach the directory at all — and the failure is completely silent. No error appears in the extension, in `chrome://policy`, or in the Smallstep dashboard; the device simply keeps its existing certificate indefinitely. + +1. In Certificate Manager, go to **Authorities**, select the authority you chose in Step 1, and download its **Root Certificate** and **Intermediate Certificate**. +2. In Google Admin, go to **Devices → Networks → Certificates**, select your target Organizational Unit, and add both certificates. Check ✅ **Enabled for Chromebook** for each. + + +
+You can confirm whether trust distribution succeeded from any machine, before touching a Chromebook: `curl -sS https://..ca.smallstep.com/acme/acme-da/directory`. A TLS error like `unable to get local issuer certificate` means the root hasn't propagated yet or wasn't uploaded. A JSON response means you're clear to continue. +
+
+ +### 3. Set the extension policy + +In Google Admin, go to **Devices → Chrome → Apps & Extensions → Users & browsers**, select your Organizational Unit, and open the Smallstep extension's **Policy for extensions**. Add `devices_ca_directory_url`, pointing at the ACME Device Attestation directory of the authority you chose: + +```json +{ + "team": { "Value": "" }, + "devices_ca_directory_url": { + "Value": "https://devices..ca.smallstep.com/acme/acme-da/directory" + } +} +``` + +Use `devices....` for the Devices authority, or `accounts....` for the Accounts authority. + +### 4. Force a fresh enrollment + +The extension will not re-enroll while it already holds a valid certificate, so a policy save alone has no effect. On the Chromebook: + +1. In Google Admin, set the extension's **Installation policy** to **Block**, and save. +2. On the device, open `chrome://policy` and click **Reload policies**. +3. In Google Admin, set the **Installation policy** back to **Force install + pin**, and save. +4. Reload policies again, then **reboot the Chromebook**. + +The reboot matters — a device can otherwise continue presenting its old certificate to an mTLS endpoint even after the new one has been issued. + +### 5. Verify certificate issuance + +On the Chromebook, go to `chrome://certificate-manager/clientcerts/platformclientcerts`. You should see two certificates: the original attestation certificate, and a new one issued by your chosen authority's Intermediate CA. Open the new certificate's **Details** and confirm the **Issuer** matches the authority you configured in Step 1. + + +
+The Smallstep dashboard's device detail page may continue to show "This device does not have any identity certificates" even after a certificate has been issued and is actively in use. ChromeOS certificates are issued over SCEP/ACME rather than the agent path this panel tracks, so it isn't a reliable place to check. Confirm issuance on the device itself, or under **Certificate Manager → Certificates → x509** in the Smallstep dashboard, where issued certificates are listed normally. +
+
+ +# Troubleshooting + +**Setting `devices_ca_directory_url` had no visible effect.** Confirm the authority's root and intermediate were uploaded to Google Admin (Step 2) before the policy was set. If they were added afterward, repeat Step 4 to force re-enrollment. + +**Only one certificate appears after re-enrollment.** Confirm the Organizational Unit in Google Admin actually matches the device — and, separately, the signed-in user's OU, since extension policy is scoped to the user's OU rather than the device's. + +**The certificate's issuer doesn't match what a downstream service expects (e.g. a RADIUS server's configured issuer pattern).** Read the issuer directly off the certificate at `chrome://certificate-manager/clientcerts/platformclientcerts` rather than assuming a value — it's the only way to be certain which authority actually signed it. + +# Next steps + +With a device identity certificate issued, continue to [ChromeOS Wi-Fi Enrollment](./protect-wireless-networks.mdx#chromeos-with-google-workspace-acme-device-attestation) to use it for passwordless 802.1X Wi-Fi authentication. From 2e603734bafcfad093f4bc38bc472a639dcf9309 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:07:43 -0500 Subject: [PATCH 09/16] Cross-link ChromeOS troubleshooting to setup and cert-identity docs --- platform/troubleshooting-agent.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/troubleshooting-agent.mdx b/platform/troubleshooting-agent.mdx index 0df22bbc..da9f6202 100644 --- a/platform/troubleshooting-agent.mdx +++ b/platform/troubleshooting-agent.mdx @@ -616,7 +616,7 @@ This may indicate the device needs to be registered and approved. See [Registeri | Check extension version | Click the Smallstep extension icon in Chrome toolbar (version shown at bottom) | | Verify device enrollment | Device must be enrolled in Google Workspace for enterprise/education | | Check policies | Navigate to `chrome://policy` and look for `Smallstep Agent for ChromeOS` | -| Verify certificates | Navigate to `chrome://certificate-manager` | +| Verify certificates | Navigate to `chrome://certificate-manager` — see [Configure ChromeOS Device Identity Certificates](../tutorials/chromeos-device-identity-certificates.mdx) if the device only has an attestation certificate rather than a usable device identity certificate | **ChromeOS Requirements:** - Device enrolled in a Google Workspace domain @@ -628,4 +628,6 @@ This may indicate the device needs to be registered and approved. See [Registeri - `ExtensionInstallForceList` containing the ChromeOS extension ID - `AttestationExtensionAllowList` containing the ChromeOS extension ID +For initial setup of these requirements and policies, see [Connect Google Workspace to Smallstep](../tutorials/connect-google-workspace-to-smallstep.mdx). + The extension retries certificate issuance every ~30 seconds. If enrollment continues to fail, contact Smallstep support. From 32c199641a602e26c4b87869b9b9a31b1a924240 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:07:54 -0500 Subject: [PATCH 10/16] Link to the device identity certificates tutorial from Confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default the extension only gets a short-lived attestation certificate, not a usable device identity certificate — point readers to the next step. --- tutorials/connect-google-workspace-to-smallstep.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index ba6b15a3..fda5cd50 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -170,3 +170,5 @@ After saving the Google Workspace connection, you will see settings for your int Within a few minutes, you should see all of your ChromeOS devices in Smallstep's [Devices](https://smallstep.com/app/?next=/devices/all) tab. A full sync is performed every 8 hours, and a partial sync every hour. +With the extension deployed, continue to [Configure ChromeOS Device Identity Certificates](./chromeos-device-identity-certificates.mdx) — by default the extension only requests a short-lived attestation certificate, which can't be used for Wi-Fi, VPN, or mTLS. + From 8d96c025b6c62a98b811014459458eb8cc6f0416 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:12:39 -0500 Subject: [PATCH 11/16] Address review feedback on device identity certificate behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The trust-distribution failure isn't a dead end: the extension retries in the background, it's just that nothing surfaces the retry or the failure to an admin. - Downgrade the curl verification tip to info severity, and clarify it runs from the admin's own machine, not the Chromebook. - devices_ca_directory_url isn't required for the default Devices authority — only needed for Accounts or a non-default Devices setup. - The dashboard not showing the device identity cert is a known gap in the ChromeOS extension, not related to ACME vs. SCEP (ChromeOS doesn't use SCEP at all). Per Herman's review comments on #545. --- tutorials/chromeos-device-identity-certificates.mdx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tutorials/chromeos-device-identity-certificates.mdx b/tutorials/chromeos-device-identity-certificates.mdx index d61d65f3..839a5d21 100644 --- a/tutorials/chromeos-device-identity-certificates.mdx +++ b/tutorials/chromeos-device-identity-certificates.mdx @@ -45,20 +45,22 @@ Both authorities support ACME Device Attestation, so the enrollment mechanics in ### 2. Distribute the authority's trust root to Google Admin -This step must happen **before** step 3, not after. Each authority's ACME directory is served over TLS using a certificate signed by that authority's own private root. If the Chromebook doesn't already trust that root, it cannot reach the directory at all — and the failure is completely silent. No error appears in the extension, in `chrome://policy`, or in the Smallstep dashboard; the device simply keeps its existing certificate indefinitely. +This step must happen **before** step 3, not after. Each authority's ACME directory is served over TLS using a certificate signed by that authority's own private root. If the Chromebook doesn't already trust that root, it cannot reach the directory — the extension retries in the background, but nothing about this is visible: no error appears in the extension, in `chrome://policy`, or in the Smallstep dashboard, and the device keeps presenting its existing certificate until the root is in place. 1. In Certificate Manager, go to **Authorities**, select the authority you chose in Step 1, and download its **Root Certificate** and **Intermediate Certificate**. 2. In Google Admin, go to **Devices → Networks → Certificates**, select your target Organizational Unit, and add both certificates. Check ✅ **Enabled for Chromebook** for each. - +
-You can confirm whether trust distribution succeeded from any machine, before touching a Chromebook: `curl -sS https://..ca.smallstep.com/acme/acme-da/directory`. A TLS error like `unable to get local issuer certificate` means the root hasn't propagated yet or wasn't uploaded. A JSON response means you're clear to continue. +You can confirm whether trust distribution succeeded from your own computer, without touching a Chromebook at all: `curl -sS https://..ca.smallstep.com/acme/acme-da/directory`. A TLS error like `unable to get local issuer certificate` means the root hasn't propagated yet or wasn't uploaded. A JSON response means you're clear to continue.
### 3. Set the extension policy -In Google Admin, go to **Devices → Chrome → Apps & Extensions → Users & browsers**, select your Organizational Unit, and open the Smallstep extension's **Policy for extensions**. Add `devices_ca_directory_url`, pointing at the ACME Device Attestation directory of the authority you chose: +The **Devices** authority is already the default: if that's what you chose in Step 1, the extension issues a device identity certificate from it automatically with just the `team` field, and you can skip to Step 4. + +`devices_ca_directory_url` is only needed if you chose the **Accounts** authority instead, or need to point at a non-default Devices authority. In Google Admin, go to **Devices → Chrome → Apps & Extensions → Users & browsers**, select your Organizational Unit, and open the Smallstep extension's **Policy for extensions**. Add `devices_ca_directory_url`, pointing at the ACME Device Attestation directory of the authority you chose: ```json { @@ -88,7 +90,7 @@ On the Chromebook, go to `chrome://certificate-manager/clientcerts/platformclien
-The Smallstep dashboard's device detail page may continue to show "This device does not have any identity certificates" even after a certificate has been issued and is actively in use. ChromeOS certificates are issued over SCEP/ACME rather than the agent path this panel tracks, so it isn't a reliable place to check. Confirm issuance on the device itself, or under **Certificate Manager → Certificates → x509** in the Smallstep dashboard, where issued certificates are listed normally. +The Smallstep dashboard's device detail page may continue to show "This device does not have any identity certificates" even after a certificate has been issued and is actively in use. This is a known gap in the ChromeOS extension today, not a sign anything went wrong — device identity certificates issued to ChromeOS devices don't yet surface on this panel. Confirm issuance on the device itself, or under **Certificate Manager → Certificates → x509** in the Smallstep dashboard, where issued certificates are listed normally.
From e5fbfda2e8a7223668061fa855d22e5fc07735cb Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:33:05 -0500 Subject: [PATCH 12/16] Stop naming the attestation certificate as a user-facing concept It's an implementation detail readers don't need: the ACME Device Attestation exchange issues it automatically, and it's never usable for mTLS or exposed in Certificate Manager. Keep the one practically useful fact (a freshly enrolled device isn't immediately mTLS-ready) without explaining why. Per Herman's review comments on #545 (L8, L27). --- .../chromeos-device-identity-certificates.mdx | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/tutorials/chromeos-device-identity-certificates.mdx b/tutorials/chromeos-device-identity-certificates.mdx index 839a5d21..2c85e194 100644 --- a/tutorials/chromeos-device-identity-certificates.mdx +++ b/tutorials/chromeos-device-identity-certificates.mdx @@ -5,7 +5,7 @@ html_title: Configure ChromeOS Device Identity Certificates for mTLS | Smallstep description: Issue mTLS-capable device identity certificates to ChromeOS devices enrolled in Google Workspace, for use in Wi-Fi, VPN, or internal application authentication. --- -Smallstep issues two different kinds of certificate to a ChromeOS device enrolled through [Google Workspace](./connect-google-workspace-to-smallstep.mdx): a short-lived **attestation certificate**, issued automatically, and a longer-lived **device identity certificate**, which is what you actually use for mTLS — Wi-Fi (802.1X), VPN, or authenticating to internal applications. +Smallstep issues a **device identity certificate** to ChromeOS devices enrolled through [Google Workspace](./connect-google-workspace-to-smallstep.mdx) — the certificate you'll use for mTLS: Wi-Fi (802.1X), VPN, or authenticating to internal applications. This guide covers issuing that device identity certificate. It's a prerequisite for [ChromeOS Wi-Fi Enrollment](./protect-wireless-networks.mdx#chromeos-with-google-workspace-acme-device-attestation) and for any other mTLS use case involving ChromeOS devices. @@ -14,23 +14,7 @@ This guide covers issuing that device identity certificate. It's a prerequisite - A completed [Connect Google Workspace to Smallstep](./connect-google-workspace-to-smallstep.mdx) integration, with devices syncing into Smallstep - The Smallstep ChromeOS extension deployed to your target Organizational Unit (covered in that same guide) -# Attestation certificate vs. device identity certificate - -A freshly enrolled ChromeOS device receives only the attestation certificate. It cannot be used for mTLS. Until you complete the steps below, the device will not have a usable identity certificate, even though it will appear fully enrolled and "high assurance" in both the Smallstep dashboard and the Admin Console. - -| | Attestation certificate | Device identity certificate | -|---|---|---| -| Issued by | Team's Intermediate CA | Devices (or Accounts) Intermediate CA | -| Lifetime | 24 hours | 30 days | -| Subject alternative name | `urn:ak:sha256:…` (attestation key) | `urn:smallstep:device:permanent-identifier:` | -| Purpose | Proves genuine hardware after Chrome Verified Access; used as the credential in the ACME Device Attestation exchange | The credential presented for mTLS | -| Available from Certificate Manager? | No — not published to customers | Yes | - - -
-Only the device identity certificate can be used for mTLS. If a device presents only the attestation certificate to an mTLS endpoint, the connection will fail — see Troubleshooting below. -
-
+A freshly enrolled device isn't ready for mTLS until you complete the steps below, even though it may already appear fully enrolled and "high assurance" in both the Smallstep dashboard and the Admin Console. # Step-by-step instructions @@ -86,7 +70,7 @@ The reboot matters — a device can otherwise continue presenting its old certif ### 5. Verify certificate issuance -On the Chromebook, go to `chrome://certificate-manager/clientcerts/platformclientcerts`. You should see two certificates: the original attestation certificate, and a new one issued by your chosen authority's Intermediate CA. Open the new certificate's **Details** and confirm the **Issuer** matches the authority you configured in Step 1. +On the Chromebook, go to `chrome://certificate-manager/clientcerts/platformclientcerts`. You should see a new certificate issued by your chosen authority's Intermediate CA (there may be other certificates listed too). Open its **Details** and confirm the **Issuer** matches the authority you configured in Step 1.
From ef3a33a24f7a871c2cab71fcb6f5328fae57264f Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:39:27 -0500 Subject: [PATCH 13/16] Reframe Step 1 as confirming, not self-service choosing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The authority is normally set up together with a Smallstep contact during onboarding, not picked independently from an open menu — this was overstating the current self-service reality. Per Herman's review comment on #545 (L39). --- tutorials/chromeos-device-identity-certificates.mdx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tutorials/chromeos-device-identity-certificates.mdx b/tutorials/chromeos-device-identity-certificates.mdx index 2c85e194..7437372a 100644 --- a/tutorials/chromeos-device-identity-certificates.mdx +++ b/tutorials/chromeos-device-identity-certificates.mdx @@ -18,14 +18,16 @@ A freshly enrolled device isn't ready for mTLS until you complete the steps belo # Step-by-step instructions -### 1. Choose an issuing authority +### 1. Confirm your issuing authority -The device identity certificate can be issued from either of two authorities in Certificate Manager: +The device identity certificate is issued from an authority in Certificate Manager, typically set up together with your Smallstep contact during onboarding rather than chosen independently. There are two conceptual patterns: -- **Devices** — binds the certificate to the device itself (subject is the hardware serial number). Use this for device-level authentication such as Wi-Fi. -- **Accounts** — binds the certificate to the Google Workspace user currently signed in to the device (subject is the user's email). Use this if you need to authenticate the user rather than the device. +- **Device-bound** (e.g. a "Devices" authority) — binds the certificate to the device itself (subject is the hardware serial number). Use this for device-level authentication such as Wi-Fi. +- **User-bound** (e.g. an "Accounts" authority) — binds the certificate to the Google Workspace user currently signed in to the device (subject is the user's email). Use this if you need to authenticate the user rather than the device. -Both authorities support ACME Device Attestation, so the enrollment mechanics in the steps below are identical either way — only the resulting certificate's identity differs. +Confirm with your Smallstep contact which authority applies to your setup before continuing — the rest of this guide refers to it as "the authority you chose." + +Both patterns support ACME Device Attestation, so the enrollment mechanics in the steps below are identical either way — only the resulting certificate's identity differs. ### 2. Distribute the authority's trust root to Google Admin From 31618a70f1c6aff7d6ccdc0448f9d1214289f5c3 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:42:08 -0500 Subject: [PATCH 14/16] Clarify when forcing a fresh enrollment is actually needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a bug: the default-authority path was pointing readers to skip to Step 4 (force re-enrollment), when there's nothing to force if no policy changed — it should skip straight to Step 5 (verify). Step 4 itself only applies when Step 3's policy change happens on a device that's already enrolled with a valid certificate (e.g. switching authorities later) — never on first-time setup. Per Herman's review comment on #545 (L77). --- tutorials/chromeos-device-identity-certificates.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tutorials/chromeos-device-identity-certificates.mdx b/tutorials/chromeos-device-identity-certificates.mdx index 7437372a..df038efa 100644 --- a/tutorials/chromeos-device-identity-certificates.mdx +++ b/tutorials/chromeos-device-identity-certificates.mdx @@ -44,7 +44,7 @@ You can confirm whether trust distribution succeeded from your own computer, wit ### 3. Set the extension policy -The **Devices** authority is already the default: if that's what you chose in Step 1, the extension issues a device identity certificate from it automatically with just the `team` field, and you can skip to Step 4. +The **Devices** authority is already the default: if that's what you chose in Step 1, the extension issues a device identity certificate from it automatically with just the `team` field, and you can skip to Step 5. `devices_ca_directory_url` is only needed if you chose the **Accounts** authority instead, or need to point at a non-default Devices authority. In Google Admin, go to **Devices → Chrome → Apps & Extensions → Users & browsers**, select your Organizational Unit, and open the Smallstep extension's **Policy for extensions**. Add `devices_ca_directory_url`, pointing at the ACME Device Attestation directory of the authority you chose: @@ -61,7 +61,7 @@ Use `devices....` for the Devices authority, or `accounts. ### 4. Force a fresh enrollment -The extension will not re-enroll while it already holds a valid certificate, so a policy save alone has no effect. On the Chromebook: +This step only applies if you completed the policy change in Step 3 — for example switching to the Accounts authority, or changing `devices_ca_directory_url` on a device that already has a valid certificate. The extension won't pick up a policy change on its own while it already holds a valid certificate, so a policy save alone has no effect. On the Chromebook: 1. In Google Admin, set the extension's **Installation policy** to **Block**, and save. 2. On the device, open `chrome://policy` and click **Reload policies**. From bcad58b5090e2dec4503e48cde3b67213de8df02 Mon Sep 17 00:00:00 2001 From: Lucas Date: Sun, 2 Aug 2026 16:48:05 -0500 Subject: [PATCH 15/16] Fix unescaped placeholder breaking MDX compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bare in prose (outside code formatting) is parsed as an unclosed JSX tag, which fails MDX compilation for the whole page. Wrap it in backticks like every other placeholder in this doc. This is pre-existing content from #528 (herman/chromeos-wif), not introduced here — flagged separately on that PR. --- tutorials/connect-google-workspace-to-smallstep.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index fda5cd50..759341f5 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -150,7 +150,7 @@ After saving the Google Workspace connection, you will see settings for your int 9. Click the newly created extension to edit it 10. Select **Force install + pin** as the **Installation policy** 11. Under **Certificate management**, enable **allow access to keys** and **Allow enterprise challenge** -12. Under **Policy for extensions**, add the following JSON, replacing with your Smallstep team slug: +12. Under **Policy for extensions**, add the following JSON, replacing `` with your Smallstep team slug: ``` { From e9f53489038f02f777d87f5f1b36559f751d58ca Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 3 Aug 2026 15:57:15 -0500 Subject: [PATCH 16/16] Finish the incomplete Installation URL sentence Step 14 trailed off with no actual value. Confirmed via live testing in Google Admin: the Installation URL field is a plain textbox that already mirrors the custom URL set in step 7, and the Update URL dropdown in step 15 genuinely does offer "Installation URL (see above)" as a literal option, so step 15 needed no change. Per Carl's review comment on #545. --- tutorials/connect-google-workspace-to-smallstep.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/connect-google-workspace-to-smallstep.mdx b/tutorials/connect-google-workspace-to-smallstep.mdx index 759341f5..d24007f8 100644 --- a/tutorials/connect-google-workspace-to-smallstep.mdx +++ b/tutorials/connect-google-workspace-to-smallstep.mdx @@ -160,7 +160,7 @@ After saving the Google Workspace connection, you will see settings for your int } ``` 13. Click **Save** in the top right corner -14. Scroll down in the side panel details, and ensure the installation URL is set to ... +14. Scroll down in the side panel details, and confirm the **Installation URL** field shows the URL you set in step 7. 15. Set the **Update URL** to **Installation URL (see above)** 16. Click **Save**