Skip to main content

Deploy ggshield at scale with a service account token

Use this page to deploy Machine Scan on managed endpoints and upload scan inventories to GitGuardian on a schedule. The same pattern works with Jamf Pro, Kandji, Intune, Workspace ONE, Mosyle, Addigy, Canonical Landscape, or configuration management tools such as Ansible, Puppet, Chef, and Salt.

Deployment model

Keep the rollout as three separate MDM jobs. It makes each part easy to audit, repair, and roll back.

JobWhat it doesGitGuardian tokenGood MDM fit
Install or update ggshieldDeploy the CLI binaryNot neededpackage deployment or remediation script
Install or update machine_scanAdd the Machine Scan plugin for the scan userOnly to install by nameaudit/remediation script
Inventory scanRun ggshield machine inventoryRequiredscheduled script, once per day

In MDM terms, an audit script checks whether a machine is compliant; a remediation script installs or repairs what is missing.

Step 1 - Create the token

Create one dedicated Service Account token with the scan, honeytokens:check, and endpoints:send scopes. One token covers both the plugin install (when you install by name) and the daily inventory upload.

ScopeWhy it is needed
scanRun the scan and install the machine_scan plugin by name
honeytokens:checkRecognize your honeytokens instead of triggering them
endpoints:sendUpload the machine inventory to your workspace

Use a dedicated Service Account token (not a personal token) and do not run ggshield auth login on fleet machines. If you stage a signed or internal plugin package instead of installing by name, the install job needs no token at all.

Store the token in your MDM secret store or secret manager, and inject it only at runtime.

Optional hardening: split into two tokens

endpoints:send is the only scope that writes into your workspace, so it is the one to contain. The daily upload runs as a single scheduled job, but the install/update job runs on every machine and is far more exposed. Give the install/update job a scan-only token and reserve scan, honeytokens:check, endpoints:send for the upload job: a leaked install token then cannot push forged inventory or hide findings in your dashboard. The cost is one extra secret to rotate. If you install the plugin from a staged package rather than by name, the install job needs no token at all, so a single upload token is already least-privilege.

Step 2 - Install and manage ggshield

Use the deployment method your fleet already trusts:

  • Jamf Pro / Kandji / Mosyle / Addigy: deploy the signed macOS package or run an install remediation script.
  • Intune: deploy the Windows installer or run the PowerShell installer; for macOS/Linux, use shell scripts or remediations.
  • Workspace ONE / RMM tools: use a managed package or script assignment.
  • Landscape / Ansible / Puppet / Chef / Salt: install the .deb/.rpm or run the official installer, then enforce the version.

For script-based macOS/Linux deployments, install only the binary first:

curl -sSfL https://raw.githubusercontent.com/GitGuardian/ggshield/main/scripts/install/install.sh | bash -s -- --install-only

Audit with:

ggshield --version # must be >= 1.51.0 to install machine_scan by name

For large fleets, prefer an internal package cache or MDM-hosted package so every machine does not download from the internet at the same time.

Step 3 - Install Machine Scan for the scan user

Machine scanning must be installed and enabled before running ggshield machine inventory. The plugin is user-scoped, so install it for the user that will run the scan (usually the logged-in user on workstations, or a dedicated target user on servers).

If your MDM can stage a signed/internal plugin package, install that package and no GitGuardian token is needed for the install job:

sudo -i -u "$TARGET_USER" -- ggshield plugin install /path/to/machine-scan-plugin.whl

If you install by name, ggshield plugin install machine_scan requires ggshield 1.51.0 or later and contacts the GitGuardian plugin catalog. Inject the service account token at runtime; do not store it with ggshield auth login on the endpoint. For EU or self-hosted instances, export GITGUARDIAN_INSTANCE in the same shell.

macOS example for Jamf/Kandji-style scripts:

loggedInUser=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && !/loginwindow/ {print $3}')

# Your MDM injects the service account token as GGSHIELD_SAT.
printf '%s\n' "$GGSHIELD_SAT" | sudo -i -u "$loggedInUser" -- /bin/zsh -c \
'IFS= read -r GITGUARDIAN_API_KEY && export GITGUARDIAN_API_KEY && exec ggshield plugin install machine_scan < /dev/null'

sudo -i -u "$loggedInUser" -- ggshield plugin list

Linux example:

# Your MDM injects the service account token as GGSHIELD_SAT.
printf '%s\n' "$GGSHIELD_SAT" | sudo -i -u "$TARGET_USER" -- /bin/bash -c \
'IFS= read -r GITGUARDIAN_API_KEY && export GITGUARDIAN_API_KEY && exec ggshield plugin install machine_scan < /dev/null'

sudo -i -u "$TARGET_USER" -- ggshield plugin list

Audit success when ggshield plugin list shows machine_scan for the scan user.

Step 4 - Run the daily inventory scan

Schedule one MDM job per day that injects the service account token at runtime and runs ggshield machine inventory as the scan user.

# Your MDM injects the service account token as GGSHIELD_SAT.
printf '%s\n' "$GGSHIELD_SAT" | sudo -i -u "$loggedInUser" -- /bin/zsh -c \
'IFS= read -r GITGUARDIAN_API_KEY && export GITGUARDIAN_API_KEY && exec ggshield machine inventory < /dev/null'

For Linux, use /bin/bash and your target user. For EU or self-hosted instances, also export GITGUARDIAN_INSTANCE inside the same shell.

This pattern keeps the token out of command-line arguments, files, logs, and ggshield auth login. That matters because supply-chain malware commonly scrapes workstations for credentials in files, shell environments, and package-manager configs. Disable shell tracing (set -x) in scripts that handle the token.

If your MDM cannot run scheduled scripts reliably, you can use launchd or a systemd timer as a fallback. Keep the token in a root-only file and remove it on uninstall.

Step 5 - Roll out and verify

Start with 10–20 monitored machines, then expand in waves (for example 1% → 10% → 25% → 50% → 100%). Spread first scans over hours, not minutes.

On a sample machine:

ggshield --version
sudo -i -u "$TARGET_USER" -- ggshield plugin list

Then trigger the MDM inventory job once. Go to Endpoint protection → Endpoints in GitGuardian and confirm the machine appears with a recent scan.

Monitor only a few signals: install success, plugin enabled, last scan time, scan duration, upload errors, and user performance feedback. To roll back, disable the scheduled inventory scan first.

For a detailed pilot checklist, see Validate and roll out.