gcp-iit attestor
Captures the GCP Instance Identity Token (a signed JWT from the GCE metadata server) and verifies its signature against Google's published JWKS, producing a tamper-evident proof of "this ran on GCE project/instance X."
| Name | gcp-iit |
|---|---|
| Predicate type | https://aflock.ai/attestations/gcp-iit/v0.1 |
| Lifecycle | prematerial |
| Default binary? | No |
| Category | ci-context (primary) |
| Recommended trace | off — no syscall tracing needed |
| Auto-attaches when |
|
The facts in this box are generated from the cilock binary's own catalog (cilock tools list). Do not hand-edit — run npm run gen:catalog.
What it captures
The full verified jwt attestor (token, header, claims, JWKS URL) plus the following GCE claims extracted from the google claim of the IIT:
project_id— GCP project (string)project_number— numeric project ID (string)zone— GCE zoneinstance_id— GCE instance IDinstance_hostname—instance_namefrom the IITinstance_creation_timestampinstance_confidentialitylicence_id— list of GCE license IDs
When the token has no google claim (Workload Identity on GKE), the attestor instead reads the GCE metadata server directly and fills in cluster_name, cluster_uid, cluster_location, plus instance/project fields parsed from the JWT email claim.
Subjects emitted: instanceid:, instancename:, projectid:, projectnumber:, clusteruid:.
When to use
Builds running on GCE VMs, GKE nodes, or Cloud Build workers. The IIT is the GCP analog of the AWS instance identity document — a strong "this ran in our project, this zone, this instance" signal signed by Google.
Flags
None. Configuration is via environment variable:
| Env var | Default | What it does |
|---|---|---|
WITNESS_GCP_JWKS_URL | https://www.googleapis.com/oauth2/v3/certs | Override the JWKS endpoint used to verify the IIT signature. |
The identity token is always fetched with audience witness-node-attestor against the default service account.
Output shape
{
"jwt": { "token": "...", "claims": { ... }, "jwksUrl": "https://www.googleapis.com/oauth2/v3/certs" },
"project_id": "my-project",
"project_number": "123456789012",
"zone": "projects/123/zones/us-central1-a",
"instance_id": "8675309",
"instance_hostname": "build-runner-01",
"instance_creation_timestamp": "1700000000",
"instance_confidentiality": "0",
"licence_id": ["1234"],
"cluster_name": "",
"cluster_uid": "",
"cluster_location": ""
}
Gotchas
- GCE-only. The identity token is fetched from
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=witness-node-attestor&format=fullwith theMetadata-Flavor: Googleheader. On any non-GCE host the request fails (no DNS, no IMDS) andAttestreturnsunable to retrieve valid identity token. - Signature verification is delegated to the
jwtattestor. The IIT is verified against Google's JWKS athttps://www.googleapis.com/oauth2/v3/certs(orWITNESS_GCP_JWKS_URL). If verification fails, the attestor fails — unverified tokens are never recorded. - Workload Identity fallback. GKE pods using Workload Identity get a token without the
googleclaim. The attestor detects this, falls back to direct metadata server lookups (/computeMetadata/v1/instance/...and/computeMetadata/v1/project/...), and parses project ID/number out of the JWTemailclaim domain. Cluster fields are only populated on this path. - Metadata responses are capped at 1 MB to bound memory if the endpoint is compromised.
- The hardcoded audience is
witness-node-attestor— verifiers asserting an audience should expect that exact string.
CLI example
See the constraint summary + reproduction recipe at https://github.com/aflock-ai/attestor-compliance-examples/tree/main/26-gcp-iit. This attestor is currently blocked or doc-only — the linked example explains why and shows the recipe to validate once the constraint is removed.
See also
- Catalog row
aws— AWS analog (EC2 instance identity document)jwt— the underlying token verification- Upstream: witness/gcp-iit.md