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.
| Job | What it does | GitGuardian token | Good MDM fit |
|---|---|---|---|
Install or update ggshield | Deploy the CLI binary | Not needed | package deployment or remediation script |
Install or update machine_scan | Add the Machine Scan plugin for the scan user | Only to install by name | audit/remediation script |
| Inventory scan | Run ggshield machine report | Required | scheduled script, once per day |
| Honeytoken plant | Run ggshield honeytoken plant | Required | scheduled 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.
| Scope | Why it is needed |
|---|---|
scan | Run the scan and install the machine_scan plugin by name |
honeytokens:check | Recognize your honeytokens instead of triggering them |
endpoints:send | Upload the machine inventory to your workspace |
honeytokens:write | Plant 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.
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/.rpmor 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.