google.iam.admin.v1.UploadServiceAccountKey
google.iam.admin.v1.UploadServiceAccountKey
Event
Uploads an external key to a service account, enabling persistent access that survives credential rotation.
Security Context
- Uploading an externally generated key to a service account gives the attacker a credential they fully control — the private key never passes through GCP, making it invisible to key creation audit trails.
- This technique provides a stealthier persistence mechanism than creating keys through IAM, since the private key material is generated outside of GCP and never logged in Cloud Audit Logs.
Log Source
Cloud Audit Logs
Sample Event
Adversarial. Draco generates an RSA-2048 keypair on his attacker-controlled host (private key stays with him forever) and uploads only the X.509 public certificate to the demiguise-inference@fantasticlogs-prod.iam.gserviceaccount.com SA. Google now accepts JWT assertions signed by Draco’s private key as valid SA credentials — and Draco never sent the private key to Google, never downloaded a JSON key from Google’s UI, never triggered the “key created” detection patterns that look at keyOrigin: GOOGLE_PROVIDED. This is the stealthier T1098.001 variant — keyOrigin: USER_PROVIDED is the killer detection field.
{ "protoPayload": { "@type": "type.googleapis.com/google.cloud.audit.AuditLog", "authenticationInfo": { "principalEmail": "draco@fantasticlogs.cloud" }, "requestMetadata": { "callerIp": "203.0.113.66", "callerSuppliedUserAgent": "google-cloud-sdk gcloud/465.0.0 command/gcloud.iam.service-accounts.keys.upload invocation-id/90000000000000000000001111110101 environment/None environment-version/None client-os/LINUX client-os-ver/(5,15,0) client-pltf-arch/x86_64 interactive/False from-script/False python/3.11.6 term/xterm-256color (Linux 5.15.0-1052-aws),gzip(gfe)", "requestAttributes": { "time": "2026-04-15T13:48:17.221987654Z", "auth": {} }, "destinationAttributes": {} }, "serviceName": "iam.googleapis.com", "methodName": "google.iam.admin.v1.UploadServiceAccountKey", "authorizationInfo": [ { "resource": "projects/-/serviceAccounts/100000000000000000100", "permission": "iam.serviceAccountKeys.create", "granted": true, "resourceAttributes": { "service": "iam.googleapis.com", "name": "projects/-/serviceAccounts/100000000000000000100", "type": "iam.googleapis.com/ServiceAccountKey" } } ], "resourceName": "projects/-/serviceAccounts/100000000000000000100", "request": { "@type": "type.googleapis.com/google.iam.admin.v1.UploadServiceAccountKeyRequest", "name": "projects/fantasticlogs-prod/serviceAccounts/demiguise-inference@fantasticlogs-prod.iam.gserviceaccount.com" }, "response": { "@type": "type.googleapis.com/google.iam.admin.v1.ServiceAccountKey", "name": "projects/fantasticlogs-prod/serviceAccounts/demiguise-inference@fantasticlogs-prod.iam.gserviceaccount.com/keys/60000000000000000001111110101", "validAfterTime": "2026-04-15T13:48:17Z", "validBeforeTime": "2027-04-15T13:48:17Z", "keyAlgorithm": "KEY_ALG_RSA_2048", "keyOrigin": "USER_PROVIDED", "keyType": "USER_MANAGED" } }, "insertId": "evt001111110101", "resource": { "type": "service_account", "labels": { "email_id": "demiguise-inference@fantasticlogs-prod.iam.gserviceaccount.com", "project_id": "fantasticlogs-prod", "unique_id": "100000000000000000100" } }, "timestamp": "2026-04-15T13:48:17.123456789Z", "severity": "NOTICE", "logName": "projects/fantasticlogs-prod/logs/cloudaudit.googleapis.com%2Factivity", "receiveTimestamp": "2026-04-15T13:48:17.567890123Z"}MITRE ATT&CK Mapping
Tactics: Persistence
- T1098.001 — Additional Cloud Credentials — Adversaries may add adversary-controlled credentials to a cloud account to maintain persistent access to victim accounts and instances within the environment.