Interactive map of Google Cloud service-agent roles and the cross-service permissions they hold, for spotting privilege-escalation surface.
Google Cloud provisions service agents: Google-managed identities that act on your behalf (the AI Platform agent, the Compute agent, and ~200 more). Each holds a role whose permissions often reach into other services. AgentMap turns that inventory into an explorable graph:
Service → Service agent (role) → Dependency (service it can touch)
and flags the permissions most useful for privilege escalation: impersonation, token minting, IAM-policy edits, key creation, secret access, deploy-with-identity.
There's no dataset in this repo. Scrape one, then build:
pip install -r scripts/requirements.txt
python3 scripts/scrape_service_agents.py # → data/all_agents_df.csv
python3 build.py # → dist/index.htmldist/index.html is a single self-contained file (D3 and the data inlined). Open
it directly, no server or install needed:
open dist/index.html # macOS
xdg-open dist/index.html # Linux
start dist\index.html # WindowsHost it by dropping the file on GitHub Pages, Cloud Storage, or any static host.
If a
file://page misbehaves, serve it over HTTP instead:cd dist && python3 -m http.server 8000
- Click a node to expand its children; click again to inspect it.
- Inspector (right panel): connections, an escalation summary, and a searchable, grouped permission list.
- Search (/) matches service, agent, and dependency names and individual permission strings, auto-expanding the graph to every match.
- Filter by service (what's on the canvas) or by dependency (only the agents
that can reach a target, e.g. "who can touch
iam?"). - ⚠ spotlight marks nodes holding escalation-relevant permissions; the inspector's Escalation filter isolates them.
- Load CSV to map your own inventory (drag-drop or button, parsed in-browser, nothing uploaded). Export dumps the current dataset as JSON.
| Key | Action | Key | Action | |
|---|---|---|---|---|
| / | Focus search | + / - | Zoom in / out | |
| e | Expand all | 0 | Fit to screen | |
| c | Collapse all | Esc | Close panel / clear search | |
| ? | About & shortcuts |
The ⚠ flags come from a small, transparent rule set (PE_RULES in
src/template.html, editable):
| Category | Matches |
|---|---|
| Impersonation / token minting | iam.serviceAccounts.actAs, getAccessToken, getOpenIdToken, implicitDelegation, signBlob, signJwt |
| IAM policy modification | *.setIamPolicy |
| Service-account key creation | iam.serviceAccounts.create, *.serviceAccountKeys.create |
| Custom role create / update | iam.roles.create, iam.roles.update |
| Secret access | secretmanager.versions.access |
| Deploy / run code with an identity | create on functions, Cloud Run, Compute, Dataflow, Composer, Cloud Build, App Engine, GKE, Deployment Manager; compute.instances.setMetadata |
scripts/scrape_service_agents.py builds data/all_agents_df.csv by reading the
service-agents index for the list of pages, then each service's
role-reference page for the cross-service permissions of the service-agent
roles documented there. A role is attributed to the page that documents it, so
roles/meshconfig.serviceAgent, listed under anthosservicemesh, groups there.
Flags: --workers, --delay, --keep-same-service, --limit, --out.
GCP changes service-agent roles over time, so re-run the scraper and rebuild whenever you want current data.
One row per (agent, permission); header required:
| Column | Meaning | Example |
|---|---|---|
Source Service |
service that owns the agent | aiplatform |
Role |
the service-agent role | roles/aiplatform.serviceAgent |
Permission |
a single IAM permission it holds | iam.serviceAccounts.actAs |
Dependency |
service the permission acts on (its prefix) | iam |
build.py --csv <path> builds from any file with this schema. The in-app Load
CSV button takes the same schema without a rebuild.
build.py builds dist/index.html from the CSV
scripts/scrape_service_agents.py scrapes the CSV from the GCP docs
scripts/requirements.txt scraper deps (requests, beautifulsoup4)
src/template.html app shell; data + D3 injected at build
src/d3.v7.min.js vendored D3 v7
MIT, see LICENSE.
