> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ultra.security/llms.txt
> Use this file to discover all available pages before exploring further.

# Secure Configuration Guide

> How to securely access, configure, operate, and decommission administrative accounts and security-relevant settings for the Ultra agentic security platform

This Secure Configuration Guide explains how to securely manage the administrative accounts and security settings of the Ultra platform. It is written for the customer administrators, including federal agency tenants, who provision and manage an Ultra organization, and it supports Ultra's pursuit of FedRAMP 20x Class B authorization (the `SCG-CSO` rule family).

The platform has two components: **Ultra Hub**, the cloud control plane where organizations, teams, workspaces, identities, governance, and guardrails are managed; and the **Ultra device**, the enforcement point that proxies MCP tool calls, applies policy, and syncs telemetry to Hub. A device runs in one of two forms: **self-hosted**, an instance of Ultra you run on a developer machine, CI runner, or your own server; or **Ultra-hosted**, enforcement Ultra operates on your behalf. The two differ in guardrail fail behavior, which is stated in full below. Security configuration is performed in Ultra Hub, which is the focus of this guide.

| Field              | Value                                                     |
| ------------------ | --------------------------------------------------------- |
| **Version**        | 1.5                                                       |
| **Last updated**   | August 19, 2026                                           |
| **Owner**          | Rob Gutierrez, Director, Security & Business Operations   |
| **Classification** | Public                                                    |
| **Contact**        | [security@ultra.security](mailto:security@ultra.security) |

## Purpose & scope

This guide covers the secure configuration of Ultra Hub: the lifecycle of top-level administrative and privileged accounts, the security-relevant settings those accounts control, the platform's secure defaults, and the programmatic interfaces for viewing, adjusting, exporting, and comparing security settings.

It is a configuration reference rather than a replacement for the underlying feature documentation. Where a topic has a canonical home, this guide links to it: [RBAC](/hub/rbac), [Enterprise SSO](/hub/sso), [Directory sync](/hub/scim), [Deploy keys](/hub/deploy-keys), [Admin Log](/hub/admin-log), [Guardrails](/hub/guardrails), [Governance](/hub/governance), and [Identities](/hub/identities).

## How to obtain and use this guide

This guide is published publicly in the Ultra documentation and is referenced, with a direct link and short description, in Ultra's FedRAMP Certification Package Overview (CPO). You can also request the current version from `security@ultra.security`.

Use it as the authoritative reference when standing up a new Ultra organization, hardening an existing one, or conducting an authorization review.

**Applying this guide (customer responsibility).** Customers implement it by mapping each recommended setting to their own tenant in **Settings > Security**, following the top-level administrative account lifecycle below, and then using the [comparison utility](#settings-comparison) to verify their configuration against Ultra's recommended baseline. Ultra is responsible for the platform controls described here; the customer (agency) is responsible for applying the recommended settings, managing their own administrative accounts, and remediating deviations.

## Account model & administrative roles

Ultra Hub enforces role-based access control (RBAC). Four roles apply to people, in decreasing order of privilege: **Owner**, **Admin**, **Member**, **Viewer**. A user's role at the organization level cascades to all teams and workspaces. **Beacon** is a separate device identity rather than a rung on that ladder; it is described below the table.

| Role      | Type                             | Security-relevant capability                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| --------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Owner** | Top-level administrative account | Full control of the organization including billing and settings. Only role that can delete the organization and the only role that can promote another user to Owner. The user who creates the organization is the first Owner.                                                                                                                                                                                                                                                           |
| **Admin** | Privileged account               | Day-to-day administration: manage members and roles (up to Admin), teams, workspaces, devices, deploy keys, SSO and SCIM (System for Cross-domain Identity Management), governance rules, and guardrails. Can view the Admin Log, but cannot alter or delete its records. Cannot delete the org or assign Owner.                                                                                                                                                                          |
| Member    | Standard user                    | Read access to org, team, and workspace, including read-only visibility of guardrail configuration. Can update workspaces, and register, link, read, update, and sync devices in them, not only devices they own. Cannot unlink, archive, or delete a device they do not own; those require a permission the role does not hold. Cannot manage users or org settings, cannot configure guardrails, and cannot view the Admin Log.                                                         |
| Viewer    | Read-only                        | Read-only visibility into the organization's teams and workspaces. Holds `org:read`, which also reaches the deploy-key inventory (metadata only, never key material) and the directory-sync endpoint, and can link a device. Note what that endpoint returns: its response body is the organization's active SCIM self-service setup-link URL, not a sync status, so a Viewer can read a link that provisions directory sync. Cannot update workspaces, manage users, or change settings. |

<Warning>
  **Roles are scoped by where the membership is granted, and an organization-level role reaches everything.** A membership recorded at the organization level resolves for every team and workspace in that organization, so an organization-level Member reaches every workspace, not only the ones they were individually added to. Grant team- or workspace-level memberships where you need a narrower blast radius.

  **One escalation path is worth knowing.** Assigning a device owner requires only `workspace:manage_gateways`, which a Member holds, and it applies to devices linked by a deploy key. A Member can therefore make themselves the owner of such a device and then reach unlink, archive, and delete through the owner path, despite not holding the delete permission directly. Treat Member as a privileged role on any workspace that carries deploy-key-linked devices.
</Warning>

**Beacon** is a device-only identity that devices use for sync operations (traces, heartbeat). Its permissions are a subset of Viewer's, so it is not a lower rung of the human ladder in the sense of holding anything a person does not. It is a separate credential class for a different reason: it is minted for a device rather than assigned to a person, and it carries no dashboard access and cannot read organization data. Treat it as a machine credential rather than as a reduced user account.

For FedRAMP purposes, the **Owner** role is the top-level administrative account that controls enterprise access to the entire offering, and the **Admin** role is the privileged account.

## Securing top-level administrative accounts

### Provisioning & secure access

Owner and Admin accounts authenticate through one of the following methods:

* **Passwordless web authentication**: email plus a one-time verification code. No stored passwords to rotate. Sessions are held in secure cookies and expire, requiring re-authentication.
* **Enterprise SSO (single sign-on, SAML 2.0 or OIDC)**: delegate authentication to your identity provider (IdP), such as Okta, Entra ID, Google Workspace, JumpCloud, PingOne, OneLogin, AD FS, Auth0, or Rippling. Recommended for all administrative accounts so that IdP-side multi-factor authentication (MFA), conditional access, and session policy apply. See [Enterprise SSO](/hub/sso).
* **CLI authentication**: `ultra login` uses the OAuth2 PKCE (Proof Key for Code Exchange) flow via the browser; tokens are stored in the local config and refreshed automatically.
* **Deploy keys**: long-lived `dk_` tokens for headless and CI devices only. These authenticate a device, not an administrator. See [Deploy keys](/hub/deploy-keys).

<Note>
  **Brute-force protection.** Ultra Hub enforces account lockout after repeated failed authentication attempts. SSO login flows carry CSRF (cross-site request forgery) state parameters and expire after 10 minutes. Self-registration into an existing organization is not permitted; access requires an invitation, SSO just-in-time (JIT) provisioning, or SCIM provisioning.
</Note>

<Tip>
  Require Enterprise SSO for all Owner and Admin accounts and enable **Enforce SSO** for your domain so administrators cannot fall back to email-code login. Ensure phishing-resistant MFA is enforced at your identity provider. Email one-time codes are not phishing-resistant on their own, which is why FedRAMP expects privileged accounts to authenticate through an IdP that enforces a phishing-resistant factor.
</Tip>

### Configuring administrative accounts

Owners and Admins configure enterprise access from **Settings > Security** and the **Settings > Members** tab:

* **Roles (RBAC).** Assign the least-privilege role. Only Owners may assign or remove Owner; Admins may assign up to Admin. The last Owner cannot be demoted or removed. See [RBAC](/hub/rbac).
* **Enterprise SSO.** Generate a setup link, complete the guided IdP wizard, **Test Connection**, then optionally **Enforce SSO** for matching domains.
* **Directory Sync (SCIM 2.0).** Automate provisioning and deprovisioning and group-to-team mapping so account lifecycle follows your corporate directory. See [Directory sync](/hub/scim).
* **Just-in-Time (JIT) provisioning.** Optionally auto-create Members on first SSO login; disable it if you require pre-provisioning via SCIM or invitation.

### Operating administrative accounts

* **Admin Log (Owner and Admin only).** Review the security event log for member provisioning and removal, SSO authentication (including SSO login failures), guardrail configuration changes, governance posture changes, and a subset of organization, workspace, and device events. Removing or disabling a security control is logged at *warning* severity. Coverage is narrower than the page's event list implies; see the gaps below before relying on it as a sole record. See [Admin Log](/hub/admin-log).
* **Identities.** Monitor every principal generating activity, its assurance tier (Authenticated, Device-attributed, Unattributed, or No activity), tool-call volume, guardrail blocks, and anomaly findings. Bring unattributed traffic under management or block it via Governance. See [Identities](/hub/identities).
* **Least privilege & separation.** Keep the number of Owners minimal; use Admin for routine administration and Member or Viewer for everyone else.

<Warning>
  **Known gaps in administrative audit coverage.** Two cases are not fully captured in the Admin Log today, and agencies conducting an authorization review should account for them:

  * Changing a member's **organization** role does not currently emit an Admin Log event. Team-scoped role changes do.
  * Events driven by SCIM directory sync are recorded without actor, target, and IP address, because the SCIM webhook runs outside the request context that supplies them.

  Both are tracked for remediation. Until they land, treat your identity provider's own logs as the authoritative record for org role changes and SCIM-driven lifecycle events.
</Warning>

### Decommissioning administrative accounts

<Warning>
  Do not overlook decommissioning. Every administrative account and credential must have a clean removal path.
</Warning>

* **SCIM deprovisioning (preferred).** Deleting a user in your IdP soft-deletes them in Ultra: the authentication identity is deactivated first (blocking login immediately), the account is marked inactive, and audit trails and memberships are preserved. Reactivation restores prior access if the user returns.
* **Manual removal.** Owners and Admins can remove a member or change their role from the **Settings > Members** tab; changes take effect immediately. Deactivated users are blocked from SSO login even if their IdP session is still valid.
* **Manual removal is not terminal while JIT is enabled.** If JIT provisioning is on for a domain, a manually removed user is re-created as a Member on their next SSO login. Remove the user at the IdP, or disable JIT, when the removal is meant to be permanent.
* **Owner protection.** The last Owner of an organization cannot be demoted or removed, preventing accidental loss of administrative control. Transfer Owner to a successor before offboarding an Owner.
* **Deploy key revocation.** Revoke deploy keys from **Settings > Security**. Devices using a revoked key lose Hub authentication on their next sync, which by default is within 60 seconds. Rotate keys periodically and scope them narrowly per workspace.
* **Device decommissioning.** Unlink or archive devices that are retired; use Governance to block a decommissioned internal MCP connector organization-wide.

<Note>
  Revocation stops Hub authentication, not traffic. A device whose deploy key has been revoked continues proxying MCP calls and enforcing its already-resolved guardrails; what it loses is telemetry sync, heartbeat, and configuration pull. Revocation does not prevent the device from starting either: `ultra start` is exempt from the CLI's Hub-auth gate, and the local check that does exist, on Ultra's own management tools, reads the credential's format rather than its validity. To stop traffic, decommission the device itself.
</Note>

## Security-relevant settings and their implications

The following settings are operable only by top-level administrative (Owner) and privileged (Admin) accounts. Recommended secure values are shown in the final column and match the [machine-readable baseline](#machine-readable-secure-configuration-guide), so a tenant configured from this table reaches exit 0 on the baseline's automated checks, leaving the manual-review items for an administrator to confirm. A tenant that deliberately runs Google sign-in is the documented exception: the baseline records it as a deviation, so such a tenant exits 1 by design and should carry the approval alongside its report. One caveat: deploy-key names are not unique per organization, and the recommended per-workspace scoping makes repeated names likely (a `ci` key in each workspace). The comparison utility reports an export it cannot read key by key as `NO DATA` rather than guessing, so a tenant following this table may still exit 1 until its key names are made distinct.

| Setting                           | Who can change                                          | Security implication                                                                                                                                                     | Recommended secure value                                                                                                                                                                                                                                                                                                                                                                   |
| --------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Enterprise SSO connection         | Owner / Admin (`org:update`)                            | Central authentication path for the org; misconfiguration can lock out users or weaken auth.                                                                             | Configured to your IdP; tested before enforcement.                                                                                                                                                                                                                                                                                                                                         |
| Enforce SSO                       | Owner / Admin (`org:update`)                            | Blocks email-code login for matching domains, forcing all auth through the IdP and its MFA.                                                                              | Enabled for corporate domain(s).                                                                                                                                                                                                                                                                                                                                                           |
| JIT provisioning (Enterprise SSO) | Owner / Admin (`org:update`)                            | Auto-creates accounts on first SSO login; convenient but reduces pre-authorization control, and re-creates manually removed users.                                       | Disabled. Where enabled deliberately, record it as an approved deviation.                                                                                                                                                                                                                                                                                                                  |
| SCIM directory sync               | Owner / Admin (`org:update`)                            | Drives account lifecycle from your IdP; webhooks are HMAC-SHA256 signed with 5-minute replay protection.                                                                 | Enabled; secret configured during SSO setup.                                                                                                                                                                                                                                                                                                                                               |
| Default provisioned role          | Owner / Admin (`org:update`)                            | The role every identity that SCIM **or** enterprise SSO creates receives; a privileged default grants privilege to everyone the identity provider provisions.            | `Member` or tighter. Ultra clamps the setting to `beacon`, `viewer`, or `member`, so it can never grant Admin or Owner.                                                                                                                                                                                                                                                                    |
| Google sign-in                    | Owner / Admin (`org:update`)                            | A second sign-in path alongside Enterprise SSO, with its own enforcement and JIT settings. Leaving it unenforced permits email-code fallback on domains it covers.       | Disabled, so Enterprise SSO is the single administrative authentication path. Where it is deliberately enabled, record it as an approved deviation and enforce it for your corporate domain(s) with its JIT provisioning off.                                                                                                                                                              |
| Google JIT provisioning           | Owner / Admin (`org:update`)                            | Independent of the Enterprise SSO JIT setting; auto-creates accounts for anyone in the configured Google domains.                                                        | Disabled.                                                                                                                                                                                                                                                                                                                                                                                  |
| Member roles (RBAC)               | Owner (any) / Admin (up to Admin), `org:manage_members` | Determines privilege; over-assignment expands blast radius.                                                                                                              | Least privilege; no more than three Owners.                                                                                                                                                                                                                                                                                                                                                |
| Deploy keys                       | Owner / Admin (`org:update`)                            | Long-lived device credentials; if leaked, allow device authentication to a workspace.                                                                                    | Per-workspace scope, expiry set, rotated, revoked when unused.                                                                                                                                                                                                                                                                                                                             |
| Guardrails (built-in & custom)    | Owner / Admin                                           | Enforce policy on every tool call. A built-in runs only once explicitly enabled; disabling one removes protection (logged at warning severity).                          | Enable all six catalog-recommended built-ins. Parameter Validation & Input Sanitization: Block. Credential & Secret Protection: Block. In-Line Authorization & Destructive Action Blocking: Block. PII (personally identifiable information) & Personal Data Protection: Redact. Tool & Server Isolation: Block. Rate Limiting: Block. Circuit Breaker is not part of the recommended set. |
| Governance                        | Owner / Admin                                           | Optional, customizable reachability control. `default_allow` admits unmatched calls; `default_deny` is zero-trust. Workspace posture overrides the organization setting. | `default_deny` on sensitive workspaces.                                                                                                                                                                                                                                                                                                                                                    |
| Admin Log access                  | Not configurable                                        | Privileged audit material; exposure would reveal security operations.                                                                                                    | Read access is restricted to Owner and Admin by RBAC, and is not a setting an administrator can change.                                                                                                                                                                                                                                                                                    |
| Organization deletion             | Not configurable                                        | Irreversible removal of the organization.                                                                                                                                | Restricted to Owner by RBAC, and is not a setting an administrator can change.                                                                                                                                                                                                                                                                                                             |

### Privileged (Admin) account settings

Beyond the Owner-exclusive controls (org deletion, Owner promotion, billing), privileged Admin accounts can operate the following security-relevant settings. Each should be exercised under least privilege:

* Create, update, and delete teams and workspaces (environment isolation boundaries).
* Manage devices: register, link, unlink, archive, delete.
* Configure and scope **guardrails** and **governance rules** at organization, workspace, or device level. For guardrails, the broadest enabled scope wins, and disabling at a broader scope falls through to a more specific enabled row; rate-limit rules and governance rules accumulate across scopes instead. Governance *posture* resolves the other way, with the workspace setting overriding the organization setting.
* Manage members and roles up to Admin, and manage SSO, SCIM, and deploy-key configuration.

## Secure defaults

A newly provisioned Ultra organization starts from the following baseline:

* **Passwordless authentication** by default: no stored passwords; account lockout on repeated failures.
* **No open self-registration**: joining an existing org requires an invitation, SSO JIT, or SCIM.
* **SCIM webhooks** require HMAC-SHA256 signatures with timestamp and replay protection; unsigned webhooks are rejected.
* **RBAC least privilege**: new invited users default to the role specified in the invitation; the Admin Log is restricted to Owner and Admin.

<Warning>
  **Built-in guardrails are not active until you enable them.** Ultra ships a catalog of built-in guardrails covering the most common MCP threats: Parameter Validation & Input Sanitization, Credential & Secret Protection, In-Line Authorization & Destructive Action Blocking, PII & Personal Data Protection, Tool & Server Isolation, Rate Limiting, and Circuit Breaker.

  The catalog marks most of these as recommended, and that recommendation carries a default mode (for example, Redact for PII & Personal Data Protection). A recommendation is not an activation: a built-in runs only once it has been explicitly enabled at organization, workspace, or device scope. Enabling the recommended set is a required hardening step after provisioning, not something the platform does on your behalf.
</Warning>

**Deviations and review.** The ability to weaken a control (for example, disabling a guardrail or lowering an enforcement mode) is restricted to Owner and Admin accounts and is recorded in the Admin Log at warning severity. Approved deviations from the recommended baseline should be documented by the administrator, and the baseline itself is reviewed and updated when Ultra's recommended security defaults change.

<Info>
  **Recommended hardening after provisioning:** enable Enterprise SSO with **Enforce SSO**, enable the recommended built-in guardrails and tune their enforcement modes (adding custom guardrails where useful), and use Governance to restrict which MCP connectors, tools, and agents are reachable, setting sensitive workspaces to `default_deny`.
</Info>

### Guardrail fail behavior

Guardrails fail closed on the local device: if a request-phase evaluator errors, panics, or is missing, the request is blocked. Four limits are worth stating precisely, because an authorization review will test them:

* **Hosted devices skip stateful evaluators.** The hosted (Postgres and OAuth) device has no shared counter store, so Rate Limiting and Circuit Breaker cannot be evaluated there. A guardrail of that type is skipped rather than failing closed.
* **Fail-closed applies to blocking modes.** A response-phase evaluator error blocks only when the configured action is block. Guardrails in redact, monitor, or alert mode keep their allow-with-signal behavior. Three response-phase paths block regardless of the configured mode: a truncated response scan, a redact-mode decision whose redaction fails, and an unrecognized mode.
* **Response-phase panics are not recovered.** The request-phase guarantee above does not extend to responses: a panic during response evaluation propagates rather than blocking.
* **A device with no local store enforces nothing.** Guardrail and governance interception is installed only when the local SQLite store opens. If it cannot (for example an unwritable database file), the device proxies traffic with no guardrail and no governance enforcement, and signals this with a startup warning rather than by refusing to start. An authorization review testing fail-closed behavior should test this case explicitly.

## Programmatic access, export & machine-readable guidance

### API to view and adjust security settings

Ultra Hub exposes REST APIs that let agencies view and adjust access- and policy-related security settings, and integrate them into their own automation and authorization-monitoring workflows:

| Setting             | API capability                                                                       |
| ------------------- | ------------------------------------------------------------------------------------ |
| Member roles (RBAC) | `PATCH /api/v1/organizations/:org/members/:member` for programmatic role assignment. |
| Guardrails          | API to view and adjust guardrail configuration and enforcement mode.                 |
| Governance          | API to view and adjust governance rules and posture.                                 |
| Enterprise SSO      | API for SSO connection configuration.                                                |
| SCIM directory sync | API to enable and report the status of directory sync.                               |

The Ultra device's local configuration (`config.yaml`) is intentionally not mutable via public API, so enforced device policy stays consistent regardless of the deployment environment.

**Authentication & authorization.** Administrative API calls require an authenticated Hub principal. Three credentials are accepted: a session token, sent as `X-Session-Token` or the session cookie; an OAuth2 access token; or a CLI API token, the latter two sent as `Authorization: Bearer`. Any of the three carries the caller's real memberships, so the same RBAC model as the UI applies. Deploy keys authenticate a device, not an administrator: they carry a workspace-scoped credential with no memberships, so they cannot call these endpoints.

Permissions differ by endpoint, and reads are not uniformly restricted:

* Role changes require `org:manage_members`.
* Enterprise SSO endpoints require `org:update`, reads included.
* SCIM and deploy-key **writes** require `org:update`, but `GET /api/v1/organizations/{org}/scim` and `GET /api/v1/organizations/{org}/deploy-keys` require only `org:read`. A Viewer can therefore read the deploy-key inventory (metadata only, never key material) and, from the SCIM endpoint, the active directory-sync setup-link URL rather than a mere status. Take this into account when assigning the Viewer role.

**Example: change a member's role.** An Owner or Admin can update a member's role with a single call:

```http theme={null}
PATCH /api/v1/organizations/{org}/members/{member}
Content-Type: application/json

{ "role": "admin" }
```

This returns the updated membership with its new role. Note the audit gap described above: this call does not currently emit an Admin Log event.

**API best practices:** rotate deploy keys and API credentials periodically, grant the least privilege required for each integration, and monitor the Admin Log for API-driven configuration changes.

### Export of security settings

Ultra Hub supports one-click export in both **CSV and JSON** on its list and log surfaces, including Traffic, Audit, Connectors, Tools, Agents, Devices, Identities, Anomaly scans, the Admin Log, and **Settings > Security**. Both formats are available wherever export exists.

Two exports matter for this guide:

* **Settings > Security** exports the organization's security posture as a normalized `Category, Setting, Value` table covering allowed domains, sign-in methods (magic links, Google, Enterprise SSO), identity provisioning, SCIM, and deploy-key metadata. Secret material (SSO connection secrets, setup-link URLs, deploy-key hashes) is deliberately excluded.
* **Identities** exports one row per principal with a Role column, which is how Owner accounts are counted.

<Note>
  Guardrail and governance configuration are **not** exportable by customers today. Both are verified in the Hub UI, and the comparison utility below reports them for manual review rather than guessing. Export coverage for these surfaces is tracked separately.
</Note>

### Machine-readable Secure Configuration Guide

A machine-readable companion to this guide, listing the recommended secure default settings for top-level administrative and privileged accounts, is provided in JSON below. Each entry declares how it can be verified:

| `verification.method` | Meaning                                                                                                       |
| --------------------- | ------------------------------------------------------------------------------------------------------------- |
| `export`              | Comparable against a customer-reachable Hub export; `export` and `field` name the source and the exact field. |
| `manual`              | No customer-reachable export exists today; verify in the Hub page named in `source`.                          |
| `platform`            | Platform behavior a customer cannot configure. Reported for information only.                                 |

For most entries `verification.field` is the exact `Category / Setting` key looked up in the export. Three kinds of entry are checked by dedicated logic instead, because no single exported row answers them, and for those the field string is descriptive only:

| Entry                         | What is actually read                                                                                                                         |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `deploy_keys.expiry_required` | The declared key count plus every per-key `Expires` row, cross-checked against each other.                                                    |
| `rbac.owner_count`            | The **Role** column of the Identities export, so `field` names a column rather than a `Category / Setting` key. Compared against `maxOwners`. |
| Any entry carrying `maxRole`  | The named field, ranked against a least-privilege ceiling (`beacon` \< `viewer` \< `member`) rather than matched to one exact value.          |

For the first two, `field` is descriptive: editing it changes nothing but the printed `source:` line. A `maxRole` entry is different, and the distinction matters if you edit the baseline: its `field` is still the exact lookup key, read before the ranking happens, so renaming it turns a passing check into `NO DATA`.

`maxOwners` and `maxRole` are the thresholds those checks compare against, and are part of the contract if you reimplement this baseline.

The `operableBy` field records who can change a setting: `owner`, `owner_admin`, or `system_default` for platform behavior.

**`verification.notApplicableWhen` (optional).** Some recommendations are moot for a given tenant. Enterprise SSO's JIT setting cannot provision anyone if Enterprise SSO is not enabled, and Google's JIT setting cannot if Google sign-in is not enabled. Where that is true, the entry names the field and value that makes it moot:

```json theme={null}
"notApplicableWhen": { "field": "Sign-in · Enterprise SSO / Enabled", "equals": false }
```

The condition applies **only when the named field is itself observed to hold that value**. A field that is absent, blank, or ambiguous in the export does not satisfy it, so a recommendation can never be switched off by data that is merely missing. If you reimplement this baseline in your own tooling, preserve that property: it is the difference between "we saw that this does not apply" and "we could not tell".

Copy the baseline directly from this page; it is also included in Ultra's FedRAMP Certification Package.

<AccordionGroup>
  <Accordion title="Recommended baseline: Ultra-SCG-baseline.json">
    ```json theme={null}
    {
      "document": "Ultra Secure Configuration Guide: machine-readable baseline",
      "version": "1.5",
      "lastUpdated": "2026-08-19",
      "owner": "Rob Gutierrez, Director, Security & Business Operations",
      "cloudServiceOffering": "Ultra Hub (control plane) and Agentic Security Platform",
      "verificationMethods": {
        "export": "Comparable against a customer-reachable Hub export. 'export' names which one.",
        "manual": "No customer-reachable export exists today; verify in the Hub UI page named in 'source'.",
        "platform": "Platform behavior a customer cannot configure. Informational only."
      },
      "notApplicableWhen": "Optional. Names another exported field and the value that makes this recommendation moot for a tenant. It applies only when that field is itself observed to hold that value, so a missing or unreadable row can never turn a recommendation off.",
      "recommendedSecureDefaults": [
        {
          "key": "auth.method",
          "title": "Enterprise SSO configured",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Enterprise SSO / Enabled"
          },
          "rationale": "Delegate Owner/Admin authentication to the corporate identity provider so its phishing-resistant MFA and session policy apply."
        },
        {
          "key": "sso.enforce",
          "title": "Enforce SSO for domain",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Enterprise SSO / Enforce SSO",
            "notApplicableWhen": {
              "field": "Sign-in · Enterprise SSO / Enabled",
              "equals": false,
              "reason": "Enterprise SSO is not enabled, so there is no connection to enforce"
            }
          },
          "rationale": "Blocks email-code fallback for corporate domains, forcing administrative authentication through the identity provider."
        },
        {
          "key": "sso.jit_provisioning",
          "title": "Just-in-Time provisioning",
          "recommendedValue": false,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Enterprise SSO / JIT provisioning",
            "notApplicableWhen": {
              "field": "Sign-in · Enterprise SSO / Enabled",
              "equals": false,
              "reason": "Enterprise SSO is not enabled, so it provisions no accounts"
            }
          },
          "rationale": "Disable where SCIM or invitation pre-provisioning is required, so accounts are authorized before they exist. Where JIT is deliberately enabled, record it as an approved deviation."
        },
        {
          "key": "sso.google.enabled",
          "title": "Google sign-in",
          "recommendedValue": false,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Google / Enabled"
          },
          "rationale": "Prefer Enterprise SSO as the single administrative authentication path. This row is always emitted, so it also verifies the premise the two Google recommendations below depend on: every notApplicableWhen anchor is itself a checked entry. A tenant that deliberately runs Google sign-in records this as an approved deviation and satisfies the two rows below; the settings table recommends the same."
        },
        {
          "key": "sso.google.enforce",
          "title": "Enforce Google sign-in for domains",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Google / Enforce for domains",
            "notApplicableWhen": {
              "field": "Sign-in · Google / Enabled",
              "equals": false,
              "reason": "Google sign-in is not enabled"
            }
          },
          "rationale": "Where Google sign-in is enabled for a corporate domain, enforce it so users on that domain cannot fall back to email-code login."
        },
        {
          "key": "sso.google.jit_provisioning",
          "title": "Google JIT provisioning",
          "recommendedValue": false,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Sign-in · Google / JIT provisioning",
            "notApplicableWhen": {
              "field": "Sign-in · Google / Enabled",
              "equals": false,
              "reason": "Google sign-in is not enabled, so it provisions no accounts"
            }
          },
          "rationale": "Google sign-in carries its own JIT setting, independent of Enterprise SSO. Left on, it auto-creates accounts for anyone in the configured domains and re-creates manually removed users."
        },
        {
          "key": "scim.directory_sync",
          "title": "SCIM 2.0 directory sync",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Directory Sync (SCIM) / Configured"
          },
          "rationale": "Drives account provisioning and deprovisioning from the corporate directory. SCIM webhooks are HMAC-SHA256 signed with replay protection."
        },
        {
          "key": "provisioning.default_role",
          "title": "Default provisioned role",
          "recommendedValue": "member or lower",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Identity Provisioning / Default provisioned role"
          },
          "rationale": "Least privilege at provisioning time. Every identity that SCIM or enterprise SSO creates receives this role. Ultra clamps the setting to beacon, viewer, or member and resolves anything else to member, so it can never grant Admin or Owner; the check confirms the effective value is member or a tighter role rather than pinning one exact value, so a tenant hardened to viewer or beacon still passes.",
          "maxRole": "member"
        },
        {
          "key": "deploy_keys.expiry_required",
          "title": "Deploy key expiry",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "security-settings",
            "source": "Settings > Security",
            "field": "Deploy Keys / Configured keys + Deploy Key · <name> / Expires"
          },
          "rationale": "Scope keys per workspace, set an expiry, rotate periodically, and revoke unused keys. A key exported with an expiry of 'Never' has none set; an organization with no deploy keys satisfies this recommendation."
        },
        {
          "key": "rbac.owner_count",
          "title": "Number of Owner accounts",
          "recommendedValue": "no more than 3",
          "maxOwners": 3,
          "operableBy": "owner",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "export",
            "export": "identities",
            "source": "Identities",
            "field": "Role"
          },
          "rationale": "Least privilege. Keep top-level administrative accounts to the minimum necessary while retaining a recovery path if one Owner is unavailable."
        },
        {
          "key": "guardrails.builtin_enabled",
          "title": "Recommended built-in guardrails enabled",
          "recommendedValue": true,
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "Built-in guardrails are a recommended starting configuration, not an active default. Each must be explicitly enabled at organization, workspace, or device scope before it runs."
        },
        {
          "key": "guardrails.parameter_validation.mode",
          "title": "Parameter Validation & Input Sanitization mode",
          "recommendedValue": "block",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "One of the six catalog-recommended built-ins. Blocks malformed and manipulated tool parameters before they reach an upstream connector."
        },
        {
          "key": "guardrails.credential_protection.mode",
          "title": "Credential & Secret Protection mode",
          "recommendedValue": "block",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "Block access to credential files, secrets in parameters, and cloud metadata endpoints."
        },
        {
          "key": "guardrails.pii_protection.mode",
          "title": "PII & Personal Data Protection mode",
          "recommendedValue": "redact",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "Redact mode is the recommended starting configuration for this guardrail."
        },
        {
          "key": "guardrails.destructive_action_blocking.mode",
          "title": "In-Line Authorization & Destructive Action Blocking mode",
          "recommendedValue": "block",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "Block destructive tool names and dangerous SQL or shell operations before they reach target systems."
        },
        {
          "key": "guardrails.tool_server_isolation.mode",
          "title": "Tool & Server Isolation mode",
          "recommendedValue": "block",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "Prevent cross-server exfiltration by blocking values read from one server from being written to another in the same session."
        },
        {
          "key": "guardrails.rate_limiting.mode",
          "title": "Rate Limiting mode",
          "recommendedValue": "block",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "manual",
            "source": "Guardrails"
          },
          "rationale": "One of the six catalog-recommended built-ins. Bounds per-connector request rates to prevent resource exhaustion. Not evaluated on hosted devices, which have no shared counter store."
        },
        {
          "key": "governance.posture",
          "title": "Governance posture",
          "recommendedValue": "default_deny",
          "operableBy": "owner_admin",
          "rule": "SCG-CSO-SDF",
          "appliesTo": "sensitive workspaces",
          "verification": {
            "method": "manual",
            "source": "Governance"
          },
          "rationale": "Zero-trust reachability for sensitive workspaces: only explicitly allowed connectors, tools, and agents reach upstreams. Workspace posture overrides the organization setting, so an organization on default_allow with sensitive workspaces on default_deny satisfies this recommendation."
        },
        {
          "key": "guardrails.fail_mode",
          "title": "Guardrail fail behavior",
          "recommendedValue": "fail_closed",
          "operableBy": "system_default",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "platform",
            "source": "Platform behavior"
          },
          "rationale": "On the local device, request-phase evaluator errors, panics, and missing evaluators block the request. Scope limits are documented in the guide."
        },
        {
          "key": "org.self_registration",
          "title": "Open self-registration",
          "recommendedValue": false,
          "operableBy": "system_default",
          "rule": "SCG-CSO-SDF",
          "verification": {
            "method": "platform",
            "source": "Platform behavior"
          },
          "rationale": "Joining an existing organization requires an invitation, SSO JIT, or SCIM. There is no open self-registration."
        },
        {
          "key": "admin_log.access",
          "title": "Admin Log access",
          "recommendedValue": "owner_admin_only",
          "operableBy": "system_default",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "platform",
            "source": "Platform behavior"
          },
          "rationale": "Privileged audit material restricted to Owner and Admin by RBAC."
        },
        {
          "key": "org.deletion",
          "title": "Organization deletion",
          "recommendedValue": "owner_only",
          "operableBy": "system_default",
          "rule": "SCG-CSO-RSC",
          "verification": {
            "method": "platform",
            "source": "Platform behavior"
          },
          "rationale": "Irreversible removal of the organization is restricted to Owner by RBAC and is not customer-configurable."
        }
      ],
      "maxOwners": "Optional. Upper bound for a counted recommendation, used by rbac.owner_count.",
      "maxRole": "Optional. Least-privilege ceiling for a role-valued recommendation, ranked beacon < viewer < member."
    }
    ```
  </Accordion>
</AccordionGroup>

### Settings comparison

Ultra provides a comparison utility (`ultra_scg_compare.py`, Python 3, no external dependencies) that ingests a tenant's exports and reports each recommended setting as matching, deviating, or requiring manual review.

<Steps>
  <Step title="Export your current settings">
    In Ultra Hub, open **Settings > Security** and use **Export** (CSV or JSON). Then open **Identities** and export it the same way, with no filters applied: the export honors whatever filters are active on the page, and a filtered roster undercounts Owner accounts. Supply both files unmodified: renaming a column or editing a value makes the affected recommendation unverifiable, and the utility reports that rather than guessing. Deploy-key expiries are read as `Never` or as the RFC 3339 timestamp the export emits.
  </Step>

  <Step title="Get the baseline and script">
    Copy the recommended baseline (`Ultra-SCG-baseline.json`) and the comparison script (`ultra_scg_compare.py`) from the collapsible blocks on this page. Both are also included in Ultra's FedRAMP Certification Package.
  </Step>

  <Step title="Run the comparison">
    ```bash theme={null}
    python ultra_scg_compare.py --baseline Ultra-SCG-baseline.json \
        --security-settings security-settings.csv \
        --identities identities.csv
    ```

    Add `--json` for a machine-readable report suitable for continuous-monitoring pipelines.
  </Step>

  <Step title="Review the output">
    Every automated check reports whether it **observed** a value, separately from whether that value matched. That split is what the four results mean:

    | Result      | Meaning                                                                                                                                                                                                                                                                                                                             |
    | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `OK`        | A value was observed and it matches the recommendation. This is the only passing result, and it is unreachable without an observation.                                                                                                                                                                                              |
    | `DEVIATION` | A value was observed and it does not match. Prints the current and recommended values, plus a reason when the value is one the utility does not recognize.                                                                                                                                                                          |
    | `NO DATA`   | No value was observed, so no judgement is possible. Every line states its own cause. Broadly: the export was not supplied; the value was absent, blank, or contradicted by a duplicate row; or the export's shape did not match what the check reads, such as a renamed column or a key count that disagrees with the rows present. |
    | `N/A`       | The recommendation does not apply to this tenant, established from a value that **was** observed (for example, Google's JIT setting when the export shows Google sign-in is not enabled).                                                                                                                                           |

    `NO DATA` is not a pass, which is why it is grouped with deviations in the exit code. `N/A` is neither, and does not affect it.

    Settings with no customer-reachable export are listed under manual review, and platform behaviors are listed for information only. Neither affects the exit code.

    Exit codes: `0` when every automated check matched, `1` when any deviated or could not be verified, and `2` when the baseline or an export was missing, unreadable, or not in the expected format. Remediate deviations in **Settings > Security**.
  </Step>
</Steps>

Sample output, from a tenant with Enforce SSO turned off and Google sign-in unused. It is a verbatim run of the script above, leading blank line included, against a **Settings > Security** and an **Identities** export in the shape Hub produces, so the values shown (`'false'`, not `'No'`) are the ones you will see in your own run:

```text theme={null}

Ultra SCG settings comparison
==============================================================================

AUTOMATED (verified from an export)
  [OK       ] Enterprise SSO configured  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Enterprise SSO / Enabled
  [DEVIATION] Enforce SSO for domain  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Enterprise SSO / Enforce SSO
              recommended: True   current: 'false'
  [OK       ] Just-in-Time provisioning  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Enterprise SSO / JIT provisioning
  [OK       ] Google sign-in  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Google / Enabled
  [N/A      ] Enforce Google sign-in for domains  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Google / Enforce for domains
              Google sign-in is not enabled
  [N/A      ] Google JIT provisioning  (SCG-CSO-RSC)
              source: Settings > Security :: Sign-in · Google / JIT provisioning
              Google sign-in is not enabled, so it provisions no accounts
  [OK       ] SCIM 2.0 directory sync  (SCG-CSO-RSC)
              source: Settings > Security :: Directory Sync (SCIM) / Configured
  [OK       ] Default provisioned role  (SCG-CSO-RSC)
              source: Settings > Security :: Identity Provisioning / Default provisioned role
  [OK       ] Deploy key expiry  (SCG-CSO-RSC)
              source: Settings > Security :: Deploy Keys / Configured keys + Deploy Key · <name> / Expires
              all 2 key(s) have an expiry
  [OK       ] Number of Owner accounts  (SCG-CSO-RSC)
              source: Identities :: Role

MANUAL REVIEW (no customer-reachable export today)
  [REVIEW   ] Recommended built-in guardrails enabled  (SCG-CSO-SDF)
              recommended: True   check in: Guardrails
  [REVIEW   ] Parameter Validation & Input Sanitization mode  (SCG-CSO-SDF)
              recommended: 'block'   check in: Guardrails
  [REVIEW   ] Credential & Secret Protection mode  (SCG-CSO-SDF)
              recommended: 'block'   check in: Guardrails
  [REVIEW   ] PII & Personal Data Protection mode  (SCG-CSO-SDF)
              recommended: 'redact'   check in: Guardrails
  [REVIEW   ] In-Line Authorization & Destructive Action Blocking mode  (SCG-CSO-SDF)
              recommended: 'block'   check in: Guardrails
  [REVIEW   ] Tool & Server Isolation mode  (SCG-CSO-SDF)
              recommended: 'block'   check in: Guardrails
  [REVIEW   ] Rate Limiting mode  (SCG-CSO-SDF)
              recommended: 'block'   check in: Guardrails
  [REVIEW   ] Governance posture  (SCG-CSO-SDF)
              recommended: 'default_deny'   check in: Governance

PLATFORM BEHAVIOR (not customer-configurable, informational)
  [INFO     ] Guardrail fail behavior  (SCG-CSO-SDF) = 'fail_closed'
  [INFO     ] Open self-registration  (SCG-CSO-SDF) = False
  [INFO     ] Admin Log access  (SCG-CSO-RSC) = 'owner_admin_only'
  [INFO     ] Organization deletion  (SCG-CSO-RSC) = 'owner_only'
------------------------------------------------------------------------------
10 automated: 7 OK, 1 deviation(s), 0 no data, 2 n/a  |  8 manual  |  4 platform
```

**Reviewing deviations.** Deviations are reviewed by the organization's Owner or Admin, remediated in **Settings > Security**, and re-verified by re-running the comparison. Ultra recommends running the comparison after any administrative change and on whatever recurring cadence your continuous-monitoring program requires, and updating the recommended baseline when Ultra's recommended security defaults change.

<AccordionGroup>
  <Accordion title="Comparison script: ultra_scg_compare.py (Python 3, no dependencies)">
    ```python theme={null}
    #!/usr/bin/env python3
    """
    ultra_scg_compare.py: Ultra Secure Configuration Guide settings comparison.

    Compares an Ultra Hub tenant's exported settings against the recommended secure
    defaults in the machine-readable SCG baseline (Ultra-SCG-baseline.json) and
    reports each recommendation as matching, deviating, or requiring manual review.

    Provided as-is, without warranty of any kind, as a convenience for authorization
    and continuous-monitoring workflows. It is a reporting aid: it does not change
    any Ultra configuration, and its output is not a compliance determination.

    Your exports contain sensitive configuration data. Treat the input files and this
    tool's output as controlled material and store them accordingly.

    USAGE
        python ultra_scg_compare.py --baseline Ultra-SCG-baseline.json \\
            --security-settings security-settings.json \\
            --identities identities.csv

        python ultra_scg_compare.py ... --json    # machine-readable report to stdout

    Both export arguments are optional. Recommendations whose export is not supplied
    are reported as NO DATA rather than silently passing.

    HOW A RESULT IS DECIDED
        Every check reports whether it actually observed a value, separately from
        whether that value matched. OK requires an observation: a recommendation
        whose value could not be read is NO DATA, never a pass. A row that is absent,
        blank, duplicated with conflicting values, or in a format this tool cannot
        read is not an observation.

        A recommendation can also be N/A: not applicable to this tenant, established
        from a value that WAS observed (for example, Enterprise SSO's JIT setting
        when the export shows Enterprise SSO is not enabled). N/A is neither a pass
        nor a failure and does not affect the exit code.

    HOW A BASELINE ENTRY BINDS TO AN EXPORT
        For most entries, verification.field is the exact "Category / Setting" key
        this tool looks up. Two entries are checked by dedicated functions instead,
        because one exported row cannot answer them, and for those the field string
        is descriptive only: deploy_keys.expiry_required (reads the key count and
        every per-key expiry row) and rbac.owner_count (reads the Identities Role
        column, so field is a column name rather than a Category / Setting key).
        Editing either changes nothing but the printed source line.

        An entry carrying maxRole is not in that group: its field is still the exact
        lookup key, read before the ranking is applied, so renaming it turns a
        passing check into NO DATA. maxOwners and maxRole are the thresholds these
        checks compare against.

    WHERE THE EXPORTS COME FROM
        --security-settings   Settings -> Security, Export (CSV or JSON). Supplies the
                              sign-in, Enterprise SSO, Google, SCIM, and deploy-key rows.
        --identities          Identities page, Export (CSV or JSON). Supplies the Role
                              column, used to count Owner accounts.

    Export the pages unmodified, and export Identities with no filters applied: the
    export honors whatever filters are active on the page, and a filtered roster
    undercounts Owner accounts.

    Some recommended settings are not present in any customer-reachable export today
    (guardrail enablement and modes, governance posture). The baseline marks these
    "manual" and this tool reports them for administrator review instead of guessing.
    Platform behaviors that a customer cannot configure are marked "platform" and are
    reported for information only. Neither affects the exit code.

    EXIT CODES
        0   every automated check matched
        1   at least one automated check deviated, or could not be verified
        2   the baseline or an export was missing, unreadable, or not in the
            expected format
    """
    import argparse
    import csv
    import json
    import sys
    from datetime import datetime

    # Values that read as "on" / "enabled" and "off" / "disabled" in an Ultra export.
    # A value in neither set is not coerced to either one: equivalent() reports it as
    # unrecognized. The empty string is deliberately absent from both -- a blank cell
    # is missing data, not an observed "off" -- and is filtered out before comparison
    # by observe(). Extend these lists only with values confirmed in a real export.
    TRUTHY = {"true", "yes", "on", "enabled", "active", "configured", "1"}
    FALSEY = {"false", "no", "off", "disabled", "inactive", "not configured",
              "none", "never", "0"}

    # Baseline entry fields this tool reads unconditionally.
    REQUIRED_ITEM_FIELDS = ("key", "title", "rule", "recommendedValue", "verification")


    class InputError(Exception):
        """A problem with a file this tool was given, reported without a traceback."""


    def norm(v):
        if isinstance(v, bool):
            return "true" if v else "false"
        if v is None:
            return ""
        return str(v).strip().lower()


    def parse_timestamp(value):
        """Parse an RFC 3339 timestamp as the export emits it, else return None."""
        text = str(value).strip()
        if not text:
            return None
        if text.endswith("Z"):
            text = text[:-1] + "+00:00"
        try:
            return datetime.fromisoformat(text)
        except ValueError:
            return None


    def equivalent(recommended, current):
        """Compare a recommended value against an observed value.

        Returns (matches, reason). Callers must establish that `current` was observed
        before calling this; it decides match-or-not, never observed-or-not. A value
        in neither TRUTHY nor FALSEY returns (False, reason) rather than being read
        as "off", so a value this tool does not understand is reported.
        """
        r, c = norm(recommended), norm(current)
        if isinstance(recommended, bool):
            if c in TRUTHY:
                return (recommended is True), None
            if c in FALSEY:
                return (recommended is False), None
            return False, f"unrecognized value {current!r}; not treated as a match"
        if r == c:
            return True, None
        return False, None


    def _normalize_row(path, row):
        if not isinstance(row, dict):
            raise InputError(f"{path}: expected each export row to be an object")
        return {(k or "").strip().lower(): ("" if v is None else str(v).strip())
                for k, v in row.items()}


    def read_export(path):
        """Read a CSV or JSON export into a list of {column: value} dicts.

        encoding="utf-8-sig" so a file saved with a UTF-8 byte-order mark parses
        rather than carrying the mark into its first column name.
        """
        try:
            if path.lower().endswith(".csv"):
                with open(path, newline="", encoding="utf-8-sig") as f:
                    return [_normalize_row(path, r) for r in csv.DictReader(f)]
            with open(path, encoding="utf-8-sig") as f:
                data = json.load(f)
        except OSError as exc:
            raise InputError(f"{path}: {exc.strerror or exc}") from exc
        except json.JSONDecodeError as exc:
            raise InputError(f"{path}: not valid JSON ({exc})") from exc
        except UnicodeDecodeError as exc:
            raise InputError(f"{path}: not UTF-8 ({exc.reason}). Re-export rather than "
                             "re-saving; the export's category names contain non-ASCII "
                             "characters that a cp1252 or UTF-16 save will mangle.") from exc
        except csv.Error as exc:
            raise InputError(f"{path}: not readable as CSV ({exc})") from exc

        if isinstance(data, dict):
            for container in ("rows", "data", "items"):
                if isinstance(data.get(container), list):
                    data = data[container]
                    break
        if not isinstance(data, list):
            raise InputError(f"{path}: expected a list of export rows")
        return [_normalize_row(path, r) for r in data]


    def load_kv_export(path):
        """Load a Settings -> Security export as {"Category / Setting": [values]}.

        The export is a normalized (Category, Setting, Value) table in both CSV and
        JSON form, so both collapse to the same map. Every value for a key is kept
        rather than the last one winning: deploy-key names are not unique within an
        organization, so two same-named keys produce two rows under one key, and
        dropping one of them would hide the key it belonged to.
        """
        out = {}
        for r in read_export(path):
            cat, setting = r.get("category", ""), r.get("setting", "")
            if not setting:
                continue
            out.setdefault(f"{cat} / {setting}".strip().lower(), []).append(r.get("value", ""))
        return out


    def load_table_export(path):
        """Load a row-per-entity export (for example the Identities export)."""
        return read_export(path)


    def observe(field, kv):
        """Read one field from the Settings -> Security export.

        Returns (observed, value, reason). observed is True only when the export
        carries exactly one non-blank value for the field. An absent row, a blank or
        whitespace-only value, and conflicting duplicate rows are all "not observed"
        and carry the reason they were not usable.
        """
        key = field.strip().lower()
        values = kv.get(key)
        if not values:
            return False, None, f"row not present in the export: {field}"
        if len({norm(v) for v in values}) > 1:
            return False, None, f"conflicting rows for {field!r} in the export"
        value = values[0]
        if norm(value) == "":
            return False, None, f"blank value for {field!r}; nothing was observed"
        return True, value, None


    def not_applicable(item, kv):
        """Decide whether a recommendation is moot for this tenant.

        The condition names another field and the value that makes this
        recommendation not apply. It fires only when that field is ITSELF observed to
        hold that value, so a missing or unreadable row can never turn a check off.
        """
        cond = item.get("verification", {}).get("notApplicableWhen")
        if not cond or kv is None:
            return False, ""
        observed, value, _ = observe(cond.get("field", ""), kv)
        if not observed:
            return False, ""
        matches, _ = equivalent(cond.get("equals"), value)
        if not matches:
            return False, ""
        return True, cond.get("reason", f"{cond.get('field')} is {norm(cond.get('equals'))}")


    def check_deploy_key_expiry(kv):
        """Check that every deploy key carries an expiry.

        "Deploy Keys / Configured keys" is the authority on how many keys exist, so
        zero keys reads as satisfied rather than unverifiable. The per-key clusters
        are cross-checked against that count in every case, including zero, so a
        count that disagrees with the rows present is reported rather than trusted.
        """
        observed, declared, reason = observe("Deploy Keys / Configured keys", kv)
        if not observed:
            return "NO DATA", None, reason
        try:
            count = int(str(declared).strip())
        except ValueError:
            return "NO DATA", None, f"unrecognized deploy key count {declared!r}"

        expiries = {k: v for k, v in kv.items()
                    if k.startswith("deploy key ") and k.endswith("/ expires")}
        total_rows = sum(len(v) for v in expiries.values())
        if len(expiries) != count:
            return ("NO DATA", f"{len(expiries)} expiry row(s) for {count} key(s)",
                    "deploy key names are not unique within an organization, so same-named "
                    "keys share one row; this export cannot be read key by key")
        if total_rows != count:
            return ("NO DATA", f"{total_rows} expiry value(s) for {count} key(s)",
                    "duplicate rows for the same deploy key name; this export cannot be "
                    "read key by key")
        if count == 0:
            return "OK", "0 deploy key(s)", "no long-lived device credentials configured"

        no_expiry, unreadable = [], []
        for key, values in sorted(expiries.items()):
            label = key.rsplit(" / ", 1)[0]
            for value in values:
                if norm(value) == "never":
                    no_expiry.append(label)
                elif parse_timestamp(value) is None:
                    unreadable.append(f"{label}: {value!r}")
        if unreadable:
            return ("DEVIATION", f"{len(unreadable)} of {count} key(s) unreadable",
                    "expiry is neither 'Never' nor an RFC 3339 timestamp, so it is not "
                    "treated as an expiry: " + "; ".join(unreadable))
        if no_expiry:
            return ("DEVIATION", f"{len(no_expiry)} of {count} key(s) have no expiry set",
                    "an expiry of 'Never' means no expiry is set")
        return "OK", f"{count} deploy key(s)", f"all {count} key(s) have an expiry"


    # Provisioning roles, least privileged first. Ultra clamps the provisioning
    # default to this set and resolves anything else to member, so a value outside
    # it means the export is not the one this check reads.
    PROVISIONING_ROLE_RANK = ["beacon", "viewer", "member"]


    def check_role_ceiling(observed, ceiling):
        """Check a role-valued recommendation against a least-privilege ceiling.

        Ranks the observed role rather than matching one exact value, so a tenant
        hardened below the ceiling passes instead of being reported as a deviation.
        """
        o, c = norm(observed), norm(ceiling)
        if o not in PROVISIONING_ROLE_RANK:
            # Ultra clamps this setting to the ranked set, so a value outside it is
            # not a role this check can place. Said plainly rather than as a bare
            # "unrecognized", since an over-privileged value is the case an auditor
            # cares about and it lands here rather than on DEVIATION.
            return "NO DATA", observed, (
                f"role {observed!r} is outside the set Ultra clamps this setting to "
                f"({', '.join(PROVISIONING_ROLE_RANK)}); if it names a more privileged "
                "role, treat it as a deviation and check the export was not edited")
        if c not in PROVISIONING_ROLE_RANK:
            return "NO DATA", observed, f"baseline maxRole {ceiling!r} is not a known role"
        if PROVISIONING_ROLE_RANK.index(o) <= PROVISIONING_ROLE_RANK.index(c):
            return "OK", observed, ("" if o == c else f"tighter than the {c} ceiling")
        return "DEVIATION", observed, f"more privileged than the recommended ceiling {c!r}"


    def check_owner_count(rows, limit):
        """Count Owner accounts in the Identities export (Role column).

        Only role values this tool recognizes are counted. An unrecognized non-blank
        role means the column is not the one this check was written against, so the
        count would be wrong: that is reported rather than counted around. An
        organization always has at least one Owner, so a count of zero likewise means
        the column was not exported as-is.
        """
        known = {"owner", "admin", "member", "viewer", "beacon", ""}
        if not rows:
            return "NO DATA", None, "the Identities export contains no rows"
        if not any("role" in r for r in rows):
            return "NO DATA", None, ("no 'Role' column in the Identities export; "
                                     "export the Identities page unmodified")
        unknown = sorted({norm(r.get("role")) for r in rows} - known)
        if unknown:
            return ("NO DATA", None,
                    "unrecognized role value(s) " + ", ".join(repr(u) for u in unknown) +
                    "; the Role column is not the one this check reads, so the count "
                    "would be wrong")
        owners = sum(1 for r in rows if norm(r.get("role")) == "owner")
        if owners == 0:
            return "NO DATA", None, ("no Owner accounts found, which cannot happen in a real "
                                     "organization; check the Role column was exported "
                                     "unmodified and unfiltered")
        return (("OK" if owners <= limit else "DEVIATION"), f"{owners} Owner account(s)",
                "" if owners <= limit else f"recommended no more than {limit}")


    def evaluate(item, security_kv, identity_rows):
        """Evaluate one baseline entry. Returns (status, current, detail)."""
        v = item["verification"]
        method = v.get("method")

        if method == "manual":
            return "MANUAL", None, v.get("source", "")
        if method == "platform":
            return "PLATFORM", item["recommendedValue"], v.get("source", "")

        if method == "export" and v.get("export") == "security-settings":
            if security_kv is None:
                return "NO DATA", None, "Settings -> Security export not supplied"
            skip, why = not_applicable(item, security_kv)
            if skip:
                return "N/A", None, why
            if item["key"] == "deploy_keys.expiry_required":
                return check_deploy_key_expiry(security_kv)
            observed, current, reason = observe(v.get("field", ""), security_kv)
            if not observed:
                return "NO DATA", None, reason
            if "maxRole" in item:
                return check_role_ceiling(current, item["maxRole"])
            ok, why_not = equivalent(item["recommendedValue"], current)
            return ("OK" if ok else "DEVIATION"), current, (why_not or "")

        if method == "export" and v.get("export") == "identities":
            if identity_rows is None:
                return "NO DATA", None, "Identities export not supplied"
            return check_owner_count(identity_rows, item.get("maxOwners", 3))

        return "NO DATA", None, "no verification method defined"


    def load_baseline(path):
        try:
            with open(path, encoding="utf-8-sig") as f:
                baseline = json.load(f)
        except OSError as exc:
            raise InputError(f"{path}: {exc.strerror or exc}") from exc
        except json.JSONDecodeError as exc:
            raise InputError(f"{path}: not valid JSON ({exc})") from exc
        except UnicodeDecodeError as exc:
            raise InputError(f"{path}: not UTF-8 ({exc.reason}). Copy the baseline from "
                             "the guide rather than re-saving it.") from exc
        items = baseline.get("recommendedSecureDefaults") if isinstance(baseline, dict) else None
        if not isinstance(items, list) or not items:
            raise InputError(f"{path}: no 'recommendedSecureDefaults' list; this does not "
                             "look like an Ultra SCG baseline")
        for i, item in enumerate(items):
            if not isinstance(item, dict):
                raise InputError(f"{path}: recommendedSecureDefaults[{i}] is not an object")
            missing = [f for f in REQUIRED_ITEM_FIELDS if f not in item]
            if missing:
                raise InputError(f"{path}: recommendedSecureDefaults[{i}] "
                                 f"({item.get('key', 'no key')}) is missing "
                                 + ", ".join(missing))
            if not isinstance(item["verification"], dict):
                raise InputError(f"{path}: recommendedSecureDefaults[{i}] "
                                 f"({item['key']}) has a non-object 'verification'")
        return items


    def main():
        ap = argparse.ArgumentParser(
            description="Compare Ultra Hub settings against the SCG baseline.")
        ap.add_argument("--baseline", required=True, help="Ultra-SCG-baseline.json")
        ap.add_argument("--security-settings",
                        help="Settings -> Security export (.json or .csv)")
        ap.add_argument("--identities", help="Identities export (.json or .csv)")
        ap.add_argument("--json", action="store_true",
                        help="emit machine-readable JSON report")
        args = ap.parse_args()

        try:
            items = load_baseline(args.baseline)
            security_kv = load_kv_export(args.security_settings) if args.security_settings else None
            identity_rows = load_table_export(args.identities) if args.identities else None
        except InputError as exc:
            print(f"error: {exc}", file=sys.stderr)
            return 2

        rows = []
        for item in items:
            status, current, detail = evaluate(item, security_kv, identity_rows)
            rows.append({
                "key": item["key"], "title": item["title"], "rule": item["rule"],
                "recommended": item["recommendedValue"], "current": current,
                "source": item["verification"].get("source", ""),
                "field": item["verification"].get("field", ""),
                "detail": detail, "status": status,
            })

        automated = [r for r in rows if r["status"] in ("OK", "DEVIATION", "NO DATA", "N/A")]
        manual = [r for r in rows if r["status"] == "MANUAL"]
        platform = [r for r in rows if r["status"] == "PLATFORM"]
        ok = sum(1 for r in automated if r["status"] == "OK")
        dev = sum(1 for r in automated if r["status"] == "DEVIATION")
        nodata = sum(1 for r in automated if r["status"] == "NO DATA")
        na = sum(1 for r in automated if r["status"] == "N/A")

        if args.json:
            print(json.dumps({
                "summary": {"automated": len(automated), "ok": ok, "deviations": dev,
                            "noData": nodata, "notApplicable": na, "manual": len(manual),
                            "platform": len(platform)},
                "results": rows}, indent=2, default=str))
        else:
            print("\nUltra SCG settings comparison")
            print("=" * 78)
            print("\nAUTOMATED (verified from an export)")
            for r in automated:
                print(f"  [{r['status']:9}] {r['title']}  ({r['rule']})")
                print(f"              source: {r['source']} :: {r['field']}")
                if r["status"] == "DEVIATION":
                    print(f"              recommended: {r['recommended']!r}   current: {r['current']!r}")
                if r["detail"]:
                    print(f"              {r['detail']}")
            print("\nMANUAL REVIEW (no customer-reachable export today)")
            for r in manual:
                print(f"  [REVIEW   ] {r['title']}  ({r['rule']})")
                print(f"              recommended: {r['recommended']!r}   check in: {r['source']}")
            print("\nPLATFORM BEHAVIOR (not customer-configurable, informational)")
            for r in platform:
                print(f"  [INFO     ] {r['title']}  ({r['rule']}) = {r['recommended']!r}")
            print("-" * 78)
            print(f"{len(automated)} automated: {ok} OK, {dev} deviation(s), {nodata} no data, "
                  f"{na} n/a  |  {len(manual)} manual  |  {len(platform)} platform")

        return 1 if (dev or nodata) else 0


    if __name__ == "__main__":
        sys.exit(main())
    ```
  </Accordion>
</AccordionGroup>

## Versioning & release history

This guide and the recommended secure default settings it documents are versioned. It is reviewed at least annually and upon any significant security change. Prior versions of the guide and the machine-readable baseline are retained by Ultra and available on request.

| Version | Effective date | Author                                                  | Review cycle                                    | Summary of changes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------- | -------------- | ------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.5     | 2026-08-19     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Corrected the settings table's default-provisioned-role row to match the baseline in name, scope and ceiling; made the Google recommendation and the table agree; corrected the claim that a `maxRole` entry's field is descriptive, since it is the lookup key; stated what the directory-sync endpoint returns to a Viewer; and extended encoding-error handling to the baseline loader.                                                                                                                                                                                                                                                                                                                                      |
| 1.4     | 2026-08-19     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Rebound the provisioning default role to the row the export actually emits and ranked it against a least-privilege ceiling instead of one exact value, restoring a reachable exit 0; extended the recommended built-in guardrail set to all six the catalog recommends; added baseline entries for Google sign-in and organization deletion; made undecodable and malformed exports exit 2 rather than 1; corrected Member device verbs and the Viewer row, replaced the Beacon justification with a credential-class argument, documented the organization-level role cascade and the device-owner escalation path, narrowed the Admin Log coverage claim to what emits today, and widened the guardrail fail-behavior limits. |
| 1.3     | 2026-08-18     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Rebuilt the comparison utility around an explicit observed-or-not decision, so no recommendation can pass on data that was never read; replaced `absentMeans` with `notApplicableWhen` and documented it; extended the baseline to Google sign-in enforcement and JIT and to the SCIM default role; corrected the deploy-key revocation mechanism, the Viewer and Member privilege rows, and the description of which credentials use `Authorization: Bearer`; adopted the connectors / devices / agents product taxonomy throughout, retaining the shipped guardrail name Tool & Server Isolation and the stable wire names used by the Hub API and its exports.                                                               |
| 1.2     | 2026-08-13     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Corrected administrative API authentication to cover session, OAuth2, and API-token credentials, and split endpoint permissions into reads and writes; corrected Admin Log access to view-only and restated Member workspace and device privileges; corrected the assurance-tier labels to the shipped names and removed the claim that revocation prevents a device restart; split the guardrail recommendation into per-guardrail modes; closed the remaining fail-open paths in the comparison utility and made a hardened tenant verifiable end to end.                                                                                                                                                                     |
| 1.1     | 2026-08-10     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Corrected guardrail activation, scope precedence, and role capabilities against product behavior; bound the machine-readable baseline to real Hub exports and added verification methods; documented known audit-coverage gaps.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| 1.0     | 2026-08-09     | Rob Gutierrez, Director, Security & Business Operations | Annual, or upon any significant security change | Initial publication supporting FedRAMP 20x Class B.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
