Skip to content

30-day pilot runbook for IT

This runbook takes an IT team from an empty server to a running pilot that covers a few hundred to a thousand people on Windows and macOS, with Chrome and Edge. It assumes you install Shield360 yourself with Docker Compose and push software with Intune (Windows) and Jamf (macOS). Each step says how to check it worked before you move on.

WeekGoal
Before day 1Server, DNS name and TLS certificate ready. Trial licence received. An IdP application and the pilot groups created.
Week 1Shield360 running, SSO working, collectors and the extension on a first wave of 20 to 50 machines. Vendor connectors added.
Weeks 2 to 3Roll out to the full pilot group. Alerts routed to Teams or Slack. Policies tuned from what the first wave showed.
Week 4Review findings and costs, export the end-of-pilot report, decide.

You need:

  • A Linux host with Docker Engine 24 or later, 4 CPU cores, 8 GB of memory and 40 GB of free disk. Give it more disk if the pilot covers more than a few hundred people.
  • A DNS name for it, for example shield360.corp.example.com, and a TLS certificate your managed devices trust. Put a reverse proxy (nginx, Traefik, an internal load balancer) in front of port 3000. Browsers, the extension and the collector all reach Shield360 over this one address.
  • Registry access and a trial licence from Shield360. See Trial licences.
  • Rights to create an application in your identity provider, a Windows PowerShell script in Intune, a Jamf policy, and browser policies.

Check Network requirements with your network team before day 1. Devices need to reach only your Shield360 server.

Get the bundle out of the image
Terminal window
aws ecr get-login-password --region us-east-2 \
| docker login --username AWS --password-stdin 959429674945.dkr.ecr.us-east-2.amazonaws.com
IMAGE=959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:2.1.0
docker pull "$IMAGE"
docker create --name shield360-bundle "$IMAGE"
docker cp shield360-bundle:/app/selfhost ./shield360
docker rm shield360-bundle
cd shield360

Use the version Shield360 gave you in place of 2.1.0.

Fill in .env
Terminal window
cp .env.example .env && chmod 600 .env

Replace every CHANGE_ME with openssl rand -hex 32, then set:

VariableValue
SHIELD360_VERSIONThe version you pulled, e.g. 2.1.0
SHIELD360_PUBLIC_URL and NEXTAUTH_URLhttps://shield360.corp.example.com
SHIELD360_ADMIN_EMAIL, SHIELD360_ADMIN_PASSWORDThe first administrator (a break-glass account)
SHIELD360_LICENSEThe trial licence, the single line starting S360L1.

.env.example lists every other setting with a comment: single sign-on, alert email, model prices, AI providers and evidence signing. Back up .env with the data: SHIELD360_VAULT_ENCRYPTION_KEY decrypts stored credentials.

Start it
Terminal window
docker compose up -d
docker compose logs -f shield360

Wait for the health check to pass (docker compose ps shows healthy). The start-up log also says whether the image can force-install the browser extension:

✅ Browser extension: signed .crx 0.1.123 (ID …) is served for device-management force-install

If it says the extension is not signed, stop and ask Shield360 for a signed image before you plan the browser rollout (step 6).

Check: open https://shield360.corp.example.com, sign in as the first administrator, and open Settings → Licence. It shows the trial as Trial — ends <date>, with every module.

The licence in SHIELD360_LICENSE is checked offline. To replace it, change .env and run docker compose up -d, or upload one in Settings → Licence (only when SHIELD360_LICENSE is empty). A trial ends after 30 days unless Shield360 set another date, then has 7 days’ grace before configuration goes read-only. Collection never stops. When the pilot becomes a purchase, install the full licence over the trial: data, settings and enrolled machines are kept. See Self-hosted licence.

Pick one:

  1. In Entra ID, create an App registration with the web redirect URI https://shield360.corp.example.com/api/auth/callback/sso, and a client secret. Add a groups claim if you will map groups to roles.
  2. In .env:
    Terminal window
    SSO_OIDC_ISSUER=https://login.microsoftonline.com/<tenant-id>/v2.0
    SSO_OIDC_CLIENT_ID=<application (client) id>
    SSO_OIDC_CLIENT_SECRET=<client secret>
    SSO_OIDC_ROLE_MAP={"<admins group id>":"admin","<security group id>":"compliance"}
  3. docker compose up -d.

Setting all three closes the email and password form. Keep the first administrator’s email the same as their IdP email so their account is reused. See Single sign-on.

Under Organisation → Members → Roles, choose who is admitted: By invitation only for a small admin group, or Anyone your identity provider signs in when the IdP application assignment is already the gate.

Check: sign in from a private window with a pilot administrator’s IdP account.

Open Settings → Collection & deployment and create an install key named for the pilot, for example pilot-2026-11. Copy it now: it is shown once.

The key only enrols machines. Each machine exchanges it for its own token, so revoking the key at the end of the rollout stops new enrolments without touching machines already enrolled. Use a separate key per wave if you want to see who came from where. See Fleet and install keys.

The collector is the shield360 CLI. Your server serves the install scripts and the binaries, so machines download nothing from the internet. It installs per user, without administrator rights. See Deploy the collector for what it schedules and collects.

Write the script

Save as Install-Shield360.ps1:

Terminal window
$env:SHIELD360_URL = "https://shield360.corp.example.com"
$env:SHIELD360_INSTALL_KEY = "<pilot install key>"
Invoke-WebRequest -UseBasicParsing "$env:SHIELD360_URL/api/cli/install.ps1" | Invoke-Expression
Add it to Intune

In the Intune admin center, open Devices → Scripts and remediations → Platform scripts → Add → Windows 10 and later, upload the script, and set:

SettingValueWhy
Run this script using the logged on credentialsYesInstalls for the signed-in person, under their profile, with coding-agent hooks
Enforce script signature checkNoThe script is yours and unsigned
Run script in 64 bit PowerShell HostYesPicks the right binary on x64 and ARM64

Assign it to the pilot device or user group.

Watch the first machines

Intune runs a platform script once per user and device. Results appear under the script’s Device status. On a machine, the Intune Management Extension log is C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log.

Jamf runs scripts as root. The collector should run as the signed-in person, so the script switches to them.

Add the script

In Jamf Pro, open Settings → Computer management → Scripts → New. Label parameter 4 Install key, and paste:

#!/bin/bash
# Shield360 collector: install and enrol for the person at the console.
export SHIELD360_URL="https://shield360.corp.example.com"
export SHIELD360_INSTALL_KEY="$4"
user=$(stat -f%Su /dev/console)
if [ -z "$user" ] || [ "$user" = "root" ] || [ "$user" = "loginwindow" ]; then
echo "Nobody is signed in; try again at the next check-in."
exit 1
fi
uid=$(id -u "$user")
launchctl asuser "$uid" sudo -u "$user" --preserve-env=SHIELD360_URL,SHIELD360_INSTALL_KEY \
/bin/sh -c 'curl -fsSL "$SHIELD360_URL/api/cli/install.sh" | sh'
Add a policy

Create a policy with the script, the install key in parameter 4, trigger Recurring Check-in, frequency Once per computer, and scope it to the pilot group. Because the script exits with an error when nobody is signed in, Jamf retries it at the next check-in.

curl does not add the quarantine attribute, so Gatekeeper does not prompt for the downloaded binary. If your server lists a signed shield360-macos.pkg (check https://<server>/api/cli/targets for "installer": true and "signed": true), you can deploy that as a Jamf package instead and run only the enrolment part of the script as the user.

Check: on a pilot machine run shield360 collector status (%USERPROFILE%\.shield360\bin\shield360.exe collector status on Windows). The machine appears under Discover → AI usage → Computers after its first heartbeat.

The extension sees prompts and AI sites in Chrome and Edge, applies your data-protection policy, and reports to your server. Your server hosts the signed extension (.crx) and its update manifest, so browsers install it from you, not from a store.

Check the build is signed

Open Settings → Collection & deployment → Browser extension. Build must say Signed. If the page warns that this server cannot force-install the extension, follow the fix it shows (usually: pull a signed Shield360 image) before going further. Device management installs only a signed .crx; an unsigned one fails silently on every machine.

Get the policy

On the same panel, create or rotate an install key so it fills in, then choose Show device policy. The panel generates the exact policy for Chrome and Edge on Windows, macOS profiles, Google Admin and Linux, with your extension ID, your update URL (https://<server>/api/extension/updates.xml), and the managed settings that tell the extension your server and key.

Windows: Intune or Group Policy
  • Intune: add a second platform script that writes the generated .reg file and runs reg import on it, with Run this script using the logged on credentials: No (it writes HKLM). Or, in a Settings catalog profile, set Google Chrome → Extensions → Configure the list of force-installed apps and extensions and Microsoft Edge → Extensions → Control which extensions are installed silently to <extension ID>;https://<server>/api/extension/updates.xml, and deliver the managed settings with the script.
  • Group Policy: import the Chrome and Edge ADMX templates, set the same force-install lists, and deliver the managed settings keys from the .reg file with Group Policy Preferences → Registry.
macOS: Jamf

Create a Configuration Profile → Application & Custom Settings → Upload payload for each preference domain the panel lists (com.google.Chrome, com.microsoft.Edge, and the extension’s managed settings domains), pasting each generated plist. Scope it to the pilot group.

Check: open chrome://policy or edge://policy on a pilot machine and reload policies; the force-install entry shows OK. chrome://extensions lists Shield360 as installed by your organisation. Under Visibility → Fleet, the browser appears as browser:<id> within a few minutes.

Collectors and the extension show what people use. The cost connectors add what the vendors billed, so the pilot report can compare the two. Both need an admin key: an organisation-level key that only an organisation owner or admin can create. It is not an ordinary API key.

Create the keys
  • OpenAI: an organisation owner signs in to the OpenAI platform and creates an admin key under the organisation’s settings (admin keys are separate from project keys).
  • Anthropic: an organisation admin signs in to the Anthropic Console and creates an Admin API key under the organisation’s settings. It starts sk-ant-admin.
Add the connectors

Open Connectors (/connectors), choose Add connector → AI spend, and add OpenAI API costs and Anthropic API costs. Paste each key, or store it in the Vault and name the entry. Save, then use the test button: it reports what it found, for example Synced $1,234.56 over 31 days.

Add any other vendors in the pilot (GitHub Copilot, Cursor, ChatGPT Enterprise, Azure OpenAI) the same way. See Spend connectors.

Open Alerts (/alerts) → Channels.

  1. In Teams, open the channel, choose ⋯ → Workflows, and pick the template Post to a channel when a webhook request is received. Choose the team and channel and copy the URL it gives (…logic.azure.com/… or …api.powerplatform.com/…).
  2. In Shield360, Add channel → Microsoft Teams, and paste the URL.

Do not use the old Incoming Webhook connector (…webhook.office.com/…): Microsoft is retiring Office 365 connectors in Teams. Shield360 still accepts those URLs so existing channels keep working until then, but set new channels up with Workflows.

Then, under Rules, send the alerts the pilot cares about (spend, guard decisions, fleet problems) to those channels. For email alerts, set ALERTS_EMAIL_FROM and an SMTP relay in .env. See Alerts.

Check: use the channel’s test button. A message arrives in the channel.

Check these at the end of week 1, then weekly:

WhereWhat you should see
Discover → AI usage → ComputersEach pilot machine, and each browser as browser:<id>, with a recent check-in. Compare the count with your Intune and Jamf assignment.
shield360 collector status on a machineScheduled yes and a recent Last report.
Installed AI softwareAI apps, local model runtimes, IDE extensions and MCP servers found on machines.
Shadow AIAI in use that no tracked subscription covers: personal plans, API keys, AI websites.
Violations and AI interactionsExtension decisions on prompts (warned, blocked, masked) once people use AI sites.
Costs → Actual vs estimateVendor-billed spend from the connectors beside the estimate from usage.
Alerts → InboxAlerts firing and reaching Teams or Slack.

If a machine is missing: check its Intune or Jamf result, then shield360 collector status on it, then the server’s log for its enrolment.

In week 4, put together what the pilot found. Everything is in the product, so the report is a set of exports, not a project:

SectionWhere it comes from
Coverage: machines and browsers enrolled against the pilot groupDiscover → AI usage → Computers
What AI is in use: apps, sites, models, coding agents, MCP serversInstalled AI software, AI inventory
Shadow AI: unsanctioned tools and personal accountsShadow AI
What it costs and whose it is: by person and department, billed against estimatedExecutive view, Costs → Actual vs estimate, CSV export
Sensitive data in prompts: what the extension warned on, blocked or maskedViolations
Findings and alertsFindings, Alerts → Inbox
Compliance evidence: a signed package with a PDF reportEvidence package. Set SHIELD360_EVIDENCE_SIGNING_KEY first so the package is signed.
  • Continue: install the full licence over the trial. Nothing is lost.
  • Stop: revoke the install key, remove the Intune scripts and Jamf policy, push shield360 collector uninstall and shield360 coding uninstall, remove the extension policies, revoke the OpenAI and Anthropic admin keys, and stop the server. Keep or delete the data volumes according to your retention policy.