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 separate MDM jobs. It makes each part easy to audit, repair, and roll back. The honeytoken plant job is optional, and scanning and honeytoken protection can be deployed independently of each other.

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 reportRequiredscheduled script, once per day
Honeytoken plantRun ggshield honeytoken plantRequiredscheduled script, weekly or folded into the daily scan

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. Add honeytokens:write if you also plant honeytokens.

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
honeytokens:writePlant honeytokens on the machine. Only needed for honeytoken protection

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 and honeytokens:write are the scopes that write into your workspace, so they are the ones to contain. The upload and plant jobs are scheduled jobs, 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 the writing scopes for the scheduled jobs: a leaked install token then cannot push forged inventory, hide findings in your dashboard, or plant honeytokens. 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 token for the scheduled jobs 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 report. 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 report as the scan user (report scans and sends in one step; see Commands).

# 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 report < /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 - Plant honeytokens (optional)

Honeytoken protection is independent from scanning. ggshield honeytoken plant reconciles the machine against GitGuardian on every run: it writes or refreshes the decoy credential profile for active honeytokens and removes the profile for revoked ones, leaving any other credential profile alone.

# 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 honeytoken plant < /dev/null'

Schedule it either in the daily inventory job or as its own job on a lower frequency. The desired state changes far less often than scan results, so a weekly pass is usually enough on large fleets. Because the command reconciles rather than appends, running it more often than necessary is harmless.

To resolve the targets on a machine without calling the API or writing to disk, run ggshield honeytoken plant --list-targets first.

For the capability itself, including how to verify placement and how to remove a honeytoken, see Protect endpoints with Honeytokens.

Step 6 - 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. If you deployed honeytoken protection, confirm the machine also reports as Protected. See Monitor coverage.

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 honeytokens, disable the plant job and run a ggshield honeytoken plant --remove-only pass to clear what is already on disk.

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