Suplantación de cuentas de servicio en GCP: seguir la cadena
Rastree la suplantación de cuentas de servicio en la auditoría de Google Cloud: GenerateAccessToken, SignBlob, serviceAccountDelegationInfo, actAs.
En resumen. La suplantación de cuentas de servicio deja dos rastros. La llamada de emisión (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt en iamcredentials.googleapis.com) es un registro Data Access, así que solo existe si el registro Data Access de IAM estaba activado. El uso del token aparece en los registros del servicio de destino con principalEmail igual a la cuenta de servicio y el verdadero autor de la llamada en authenticationInfo.serviceAccountDelegationInfo. Lea ambos y busque a quién se concedió Token Creator o Service Account User en primer lugar.
La suplantación es legítima e incluso recomendable: sustituye las claves descargables por tokens de corta duración. También es una de las vías de escalada de privilegios más usadas en Google Cloud, porque el permiso que la permite, iam.serviceAccounts.getAccessToken, se concede a menudo de forma amplia. La investigación de Rhino Security Labs sobre escalada de privilegios en GCP enumera getAccessToken, signBlob, signJwt e implicitDelegation como métodos de escalada distintos.
Suplantación frente a uso de una clave
Google traza la línea con claridad en su documentación sobre suplantación: la suplantación implica dos identidades (el principal autenticado y la cuenta de servicio), mientras que autenticarse con una clave implica solo una. Para quien investiga:
| Mecanismo | Qué lo identifica en los registros |
|---|---|
| Clave gestionada por el usuario | authenticationInfo.serviceAccountKeyName (vea clave filtrada) |
| Suplantación (token emitido mediante la API IAM Credentials) | serviceAccountDelegationInfo en las llamadas, GenerateAccessToken en los registros Data Access |
| Cuenta de servicio asociada (VM, Cloud Run, Cloud Functions) | Llamadas como la cuenta de servicio, normalmente desde la IP de la carga de trabajo, sin nombre de clave ni delegación |
| Workload Identity Federation | principalSubject del tipo principal://… o información de delegación con un principal de terceros |
La tercera fila importa: un token robado del servidor de metadatos de una VM (T1552.005) no es suplantación en los registros; parece la cuenta de servicio de la VM, pero llamada desde otro lugar.
Rastro 1: la llamada de emisión
Según la página de Google sobre el registro de auditoría de Service Account Credentials, estos métodos se registran en cloudaudit.googleapis.com/data_access con el servicio iamcredentials.googleapis.com. Al habilitar los registros de auditoría Data Access para la API de IAM, también se habilitan para esta API.
protoPayload.serviceName="iamcredentials.googleapis.com"
protoPayload.methodName=("GenerateAccessToken" OR "GenerateIdToken" OR "SignBlob" OR "SignJwt")
En estas entradas, principalEmail es quien llama (el verdadero actor o el eslabón anterior de la cadena) y la cuenta de servicio de destino aparece en resource.labels.email_id y resourceName, como muestran los registros de ejemplo de Google. SignBlob y SignJwt merecen una atención especial: un JWT firmado como cuenta de servicio puede canjearse por un token, y firmar blobs permite falsificar URL firmadas.
Rastro 2: las llamadas hechas con el token
Cualquier llamada a la API hecha con un token suplantado lleva la cadena:
"authenticationInfo": {
"principalEmail": "deployer@PROJECT.iam.gserviceaccount.com",
"serviceAccountDelegationInfo": [
{ "firstPartyPrincipal": { "principalEmail": "alice@example.com" } }
]
}
Esto está disponible en los registros Admin Activity, que están siempre activos. Así que, aunque la llamada de emisión sea invisible, las escrituras hechas con el token siguen nombrando al verdadero autor. A menudo es el único rastro que tendrá.
Cadenas
La suplantación puede encadenarse: A suplanta a B, que suplanta a C (el parámetro delegates de GenerateAccessToken; cada salto necesita permiso sobre la siguiente cuenta de servicio, que el rol Token Creator proporciona). La cadena se registra en serviceAccountDelegationInfo como un array. Para reconstruirla:
- Parta de la llamada final y lea la lista de delegación.
- Para cada salto, busque la vinculación de IAM que lo permitió: quién tiene
roles/iam.serviceAccountTokenCreatorsobre qué cuenta de servicio, y desde cuándo. - Compruebe si alguna de esas vinculaciones se añadió durante la ventana del incidente (
bindingDeltasADD, vea abuso de SetIamPolicy).
En el tercer paso es donde se ven los ataques: una identidad comprometida con pocos privilegios se concede Token Creator sobre una cuenta de servicio poderosa y luego emite tokens para ella (T1098.003 y después T1550.001).
actAs: suplantación a través de un recurso
El rol Service Account User (roles/iam.serviceAccountUser) concede iam.serviceAccounts.actAs: el derecho a asociar una cuenta de servicio a un recurso. Alguien con actAs sobre una cuenta de servicio poderosa y compute.instances.create puede arrancar una VM que se ejecute con esa cuenta y leer su token desde el servidor de metadatos. Los registros de ejemplo de Google muestran la comprobación como una entrada authorizationInfo con "permission": "iam.serviceAccounts.actAs" y "granted": true en la llamada de creación del recurso.
Así que, al revisar creaciones de VM, Cloud Run o Cloud Functions durante un incidente, lea authorizationInfo y la cuenta de servicio indicada en la solicitud, no solo quién creó el recurso.
Señales de alerta
- Un usuario humano o una IP externa que emite tokens para una cuenta de servicio que normalmente solo usa una carga de trabajo.
- Llamadas
GenerateAccessTokenque empiezan justo después de una concesión de Token Creator. - Cadenas largas con una cuenta de servicio intermedia que no tiene responsable.
SignJwtoSignBlobdesde principales que no tienen motivo para firmar nada.- Llamadas con información de delegación de un principal ajeno a sus dominios.
Qué muestra el analizador
En el analizador:
sa_impersonation(media, escalada de privilegios, T1550.001) se activa con las llamadasGenerateAccessToken,GenerateIdToken,SignBlobySignJwtque tienen éxito, excluidos los agentes de servicio gestionados por Google.token_creator_granted(alta) se activa con unADDde Token Creator, Service Account User, Service Account Key Admin o Workload Identity User.- La pestaña Entidades muestra, para cada principal, las identidades que lo suplantaron (a partir de
serviceAccountDelegationInfo), y el detalle de la entrada de registro muestra «Suplantada por».
El límite es el ya mencionado: sin registros Data Access de IAM, solo existe el segundo rastro, y la herramienta avisa cuando una exportación no contiene ningún registro Data Access. Vea limitaciones de los registros Data Access.
Remediación
Quite las vinculaciones Token Creator / Service Account User que nadie necesita, concédalas preferiblemente sobre cuentas de servicio concretas y no sobre el proyecto, y revise qué principales pueden suplantar sus cuentas de servicio con más privilegios. La página de Google sobre permisos de cuentas de servicio detalla lo que permite cada rol.
Preguntas frecuentes
¿Cómo veo quién suplantó una cuenta de servicio en Google Cloud?
En dos lugares. La llamada que emite el token (GenerateAccessToken, GenerateIdToken, SignBlob, SignJwt en iamcredentials.googleapis.com) es un registro Data Access cuyo principalEmail es el verdadero autor de la llamada. Las llamadas hechas con el token resultante indican el verdadero autor en authenticationInfo.serviceAccountDelegationInfo.
¿Por qué no encuentro GenerateAccessToken en mis registros?
Porque se registra como registro de auditoría Data Access (ADMIN_READ), desactivado por defecto. Al habilitar los registros Data Access para la API de IAM, también se habilitan para la API Service Account Credentials.
Lecturas recomendadas
- Suplantación de cuentas de servicio — documentación de Google Cloud.
- Registros de ejemplo para cuentas de servicio — documentación de Google Cloud.
- MITRE ATT&CK T1550.001, Application Access Token.