Recopila registros de auditoría de Azure DevOps
Descripción general
Este analizador controla los registros de auditoría de Azure DevOps en formato JSON. Extrae campos de estructuras JSON anidadas y de nivel superior, y los asigna al UDM. La lógica condicional basada en valores de campos específicos categoriza los eventos y enriquece el resultado con información de seguridad pertinente. El analizador también controla los mensajes con formato no JSON intentando extraer una carga útil JSON con patrones de Grok.
Antes de comenzar
Asegúrate de cumplir con los siguientes requisitos previos:
- Instancia de Google SecOps
- Una organización activa de Azure DevOps
- Acceso con privilegios a la organización de Azure DevOps y a Azure
Configura feeds
Existen dos puntos de entrada diferentes para configurar feeds en la plataforma de Google SecOps:
- Configuración de SIEM > Feeds
- Centro de contenido > Paquetes de contenido
Configura feeds desde Configuración del SIEM > Feeds
Para configurar varios feeds para diferentes tipos de registros dentro de esta familia de productos, consulta Cómo configurar feeds por producto.
Para configurar un solo feed, sigue estos pasos:
- Ve a SIEM Settings > Feeds.
- Haz clic en Agregar feed nuevo.
- En la siguiente página, haz clic en Configurar un solo feed.
- En el campo Nombre del feed, ingresa un nombre para el feed (por ejemplo, Registros de Azure DevOps).
- Selecciona Webhook como el Tipo de origen.
- Selecciona Auditoría de Azure DevOps como el Tipo de registro.
- Haz clic en Siguiente.
- Opcional: Especifica valores para los siguientes parámetros de entrada:
- Delimitador de división: Es el delimitador que se usa para separar las líneas de registro, como
\n
. - Espacio de nombres del recurso: Es el espacio de nombres del recurso.
- Etiquetas de transferencia: Es la etiqueta que se aplica a los eventos de este feed.
- Delimitador de división: Es el delimitador que se usa para separar las líneas de registro, como
- Haz clic en Siguiente.
- Revisa la configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.
- Haz clic en Generar clave secreta para generar una clave secreta que autentique este feed.
- Copia y almacena la clave secreta. No podrás volver a ver esta clave secreta. Si es necesario, puedes regenerar una clave secreta nueva, pero esta acción hace que la clave secreta anterior quede obsoleta.
- En la pestaña Detalles, copia la URL del extremo del feed del campo Información del extremo. Debes especificar esta URL de extremo en tu aplicación cliente.
- Haz clic en Listo.
Configura feeds desde el Centro de contenido
Especifica valores para los siguientes campos:
- Delimitador de división: Es el delimitador que se usa para separar las líneas de registro, como
\n
.
Opciones avanzadas
- Nombre del feed: Es un valor completado previamente que identifica el feed.
- Tipo de fuente: Es el método que se usa para recopilar registros en Google SecOps.
- Espacio de nombres del recurso: Es el espacio de nombres del recurso.
- Etiquetas de transferencia: Es la etiqueta que se aplica a los eventos de este feed.
- Haz clic en Siguiente.
- Revisa la configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.
- Haz clic en Generar clave secreta para generar una clave secreta que autentique este feed.
Crea una clave de API para el feed del webhook
Ve a Google Cloud consola > Credenciales.
Haz clic en Crear credenciales y selecciona Clave de API.
Restringe el acceso a la clave de API a la API de Google Security Operations.
Especifica la URL del extremo
- En tu aplicación cliente, especifica la URL del extremo HTTPS que se proporciona en el feed de webhook.
Para habilitar la autenticación, especifica la clave de API y la clave secreta como parte del encabezado personalizado con el siguiente formato:
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
Recomendación: Especifica la clave de API como un encabezado en lugar de hacerlo en la URL. Si tu cliente de webhook no admite encabezados personalizados, puedes especificar la clave de API y la clave secreta con parámetros de búsqueda en el siguiente formato:
ENDPOINT_URL?key=API_KEY&secret=SECRET
Reemplaza lo siguiente:
ENDPOINT_URL
: Es la URL del extremo del feed.API_KEY
: Es la clave de API para autenticarse en Google Security Operations.SECRET
: Es la clave secreta que generaste para autenticar el feed.
Configura la función de auditoría en Azure DevOps
- Accede a tu organización (
https://dev.azure.com/{yourorganization}
). - Selecciona el ícono de ajustes para Configuración de la organización.
- En Seguridad, selecciona Políticas.
- Activa el botón Registrar eventos de auditoría.
Configura un tema de Event Grid en Azure
- Accede al portal de Azure.
- Busca Event Grid y accede a él.
- Ubica Topics en Custom events.
- Haz clic en + Crear.
- Selecciona tu suscripción y tu grupo de recursos. Proporciona un nombre (por ejemplo,
DevopsAuditLog
) y selecciona la región. Haz clic en Revisar y crear. - Accede al nuevo tema y copia la URL del extremo del tema.
- Ve a Configuración > Claves de acceso y copia la Clave 1.
Configura el flujo de registros de Azure DevOps en Event Grid
- Accede a tu organización (
https://dev.azure.com/{yourorganization}
). - Selecciona el ícono de ajustes para Configuración de la organización.
- Selecciona Auditing.
- Ve a la pestaña Flujos y selecciona Flujo nuevo > Event Grid.
- Ingresa el extremo del tema y la clave de acceso que creaste en Configura un tema de Event Grid en Azure.
Configura un webhook en Azure DevOps para Google SecOps
- En el portal de Azure, busca Event Grid y accede a él.
- Selecciona el tema creado anteriormente.
- Ve a Entities > Event Subscription.
- Haz clic en + Suscripción a eventos.
- Proporciona un nombre descriptivo (por ejemplo, *
Google SecOps Integration
). - Selecciona Web Hook y haz clic en Configurar un extremo.
- Configura el extremo:
- Extremo del suscriptor: Ingresa la URL del extremo de API de Google SecOps.
- En la sección Encabezados HTTP, agrega los siguientes encabezados:
- Encabezado 1:
- Key:
X-goog-api-key
- Valor: Es la clave de API que creaste en la sección Crea una clave de API para el feed del webhook.
- Key:
- Encabezado 2:
- Key:
X-Webhook-Access-Key
- Value: Es la clave secreta que generaste en la sección Configura un feed en Google SecOps para transferir los registros de Azure DevOps.
- Key:
- Encabezado 1:
- Configura el encabezado Content-Type como
application/json
.
- Haz clic en Crear.
Tabla de asignación de UDM
Campo de registro | Asignación de UDM | Lógica |
---|---|---|
ActivityId |
metadata.product_log_id |
Se asigna directamente desde el campo Id en el registro sin procesar cuando el campo records no está presente, o desde el campo ActivityId dentro del objeto data cuando records está presente. |
ActionId |
metadata.product_event_type |
Se asigna directamente desde el campo ActionId dentro del objeto data . |
ActorCUID |
additional.fields |
Se incluye como un campo adicional con la clave "CUID del actor". |
ActorDisplayName |
principal.user.user_display_name |
Se asigna directamente desde el campo ActorDisplayName si no es "Azure DevOps Service". Si es "Azure DevOps Service", se agrega como etiqueta a principal.resource.attribute.labels . |
ActorUPN |
principal.user.email_addresses |
Se asigna directamente desde el campo ActorUPN si coincide con un patrón de dirección de correo electrónico. |
ActorUserId |
principal.user.userid |
Se asigna directamente desde el campo ActorUserId . |
Area |
target.application |
Se usa para construir el campo target.application anteponiendo "DevOps " al valor de Area . |
AuthenticationMechanism |
extensions.auth.auth_details , security_result.rule_id |
Se analiza para extraer los detalles de autenticación y el ID de la regla. Los detalles de autenticación se asignan a extensions.auth.auth_details . El ID de regla extraído se asigna a security_result.rule_id . |
CategoryDisplayName |
security_result.action_details |
Se asigna directamente a security_result.action_details . |
City |
principal.location.city |
Se asigna directamente desde el campo City . |
Conditions |
additional.fields |
Se agregó como un campo adicional con la clave "Conditions". |
Country |
principal.location.country_or_region |
Se asigna directamente desde el campo Country . |
Data.* |
Varios | Los campos dentro del objeto Data se asignan a diferentes campos del UDM según sus nombres y contexto. Consulta los ejemplos específicos a continuación. |
Data.AccessLevel |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "AccessLevel". |
Data.AgentId |
target.resource.product_object_id |
Se asigna a target.resource.product_object_id si PipelineId y AuthorizationId no están presentes. |
Data.AgentName |
target.resource.name |
Se asigna a target.resource.name si no están presentes PipelineName , NamespaceName y DisplayName . |
Data.AuthorizationId |
target.resource.product_object_id |
Se asigna a target.resource.product_object_id si PipelineId no está presente. |
Data.CallerProcedure |
additional.fields |
Se agregó como un campo adicional con la clave "CallerProcedure". |
Data.CheckSuiteId |
additional.fields |
Se agregó como un campo adicional con la clave "CheckSuiteId". |
Data.CheckSuiteStatus |
additional.fields |
Se agregó como un campo adicional con la clave "CheckSuiteStatus". |
Data.ConnectionId |
additional.fields |
Se agregó como un campo adicional con la clave "ConnectionId". |
Data.ConnectionName |
additional.fields |
Se agregó como un campo adicional con la clave "ConnectionName". |
Data.ConnectionType |
additional.fields |
Se agregó como un campo adicional con la clave "ConnectionType". |
Data.DefinitionId |
additional.fields |
Se agregó como un campo adicional con la clave "DefinitionId". |
Data.DeploymentResult |
additional.fields |
Se agregó como un campo adicional con la clave "DeploymentResult". |
Data.DisplayName |
target.resource.name |
Se asigna a target.resource.name si PipelineName y NamespaceName no están presentes. |
Data.EndpointIdList |
additional.fields |
Se agregó como un campo adicional con la clave "EndpointIdList". |
Data.EnvironmentName |
additional.fields |
Se agregó como un campo adicional con la clave "EnvironmentName". |
Data.Filter.continuationToken |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "continuation_token". |
Data.Filter.endTime |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "filter_end_time". |
Data.Filter.startTime |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "filter_start_time". |
Data.FinishTime |
additional.fields |
Se agregó como un campo adicional con la clave "FinishTime". |
Data.GroupId |
target.group.product_object_id |
Se asigna directamente a target.group.product_object_id cuando Data.Updates.0.GroupId no está presente. |
Data.GroupName |
target.group.group_display_name |
Se asigna directamente a target.group.group_display_name . |
Data.JobName |
additional.fields |
Se agregó como un campo adicional con la clave "JobName". |
Data.MemberId |
target.user.userid |
Se asigna directamente a target.user.userid cuando Data.Updates.0.MemberId no está presente. |
Data.MemberDisplayName |
target.user.user_display_name |
Se asigna directamente a target.user.user_display_name . |
Data.NamespaceId |
target.resource.product_object_id |
Se asigna a target.resource.product_object_id si no están presentes PipelineId , AuthorizationId y AgentId . |
Data.NamespaceName |
target.resource.name |
Se asigna a target.resource.name si PipelineName no está presente. |
Data.ownerDetails |
additional.fields |
Se agregó como un campo adicional con la clave "OwnerDetails". |
Data.OwnerId |
additional.fields |
Se agregó como un campo adicional con la clave "OwnerId". |
Data.PipelineId |
target.resource.product_object_id |
Se asigna directamente a target.resource.product_object_id . |
Data.PipelineName |
target.resource.name |
Se asigna directamente a target.resource.name . |
Data.PipelineRevision |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "PipelineRevision". |
Data.PipelineScope |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "PipelineScope". |
Data.PlanType |
additional.fields |
Se agregó como un campo adicional con la clave "PlanType". |
Data.PreviousAccessLevel |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "PreviousAccessLevel". |
Data.PublisherName |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "PublisherName". |
Data.Reason |
additional.fields |
Se agregó como un campo adicional con la clave "Reason". |
Data.ReleaseId |
additional.fields |
Se agregó como un campo adicional con la clave "ReleaseId". |
Data.ReleaseName |
additional.fields |
Se agregó como un campo adicional con la clave "ReleaseName". |
Data.RequesterId |
additional.fields |
Se agregó como un campo adicional con la clave "RequesterId". |
Data.RetentionLeaseId |
additional.fields |
Se agregó como un campo adicional con la clave "RetentionLeaseId". |
Data.RetentionOwnerId |
additional.fields |
Se agregó como un campo adicional con la clave "RetentionOwnerId". |
Data.RunName |
additional.fields |
Se agregó como un campo adicional con la clave "RunName". |
Data.Scopes |
target.resource.attribute.labels |
Se agregan como etiquetas con la clave "Scope". |
Data.StageName |
additional.fields |
Se agregó como un campo adicional con la clave "StageName". |
Data.StartTime |
additional.fields |
Se agregó como un campo adicional con la clave "StartTime". |
Data.TargetUser |
target.user.userid |
Se asigna directamente a target.user.userid . |
Data.Timestamp |
metadata.event_timestamp |
Se analizó y se asignó a metadata.event_timestamp . |
Data.TokenType |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "TokenType". |
Data.Updates.0.GroupId |
target.group.product_object_id |
Se asigna directamente a target.group.product_object_id . |
Data.Updates.0.MemberId |
target.user.userid |
Se asigna directamente a target.user.userid . |
Data.ValidFrom |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "ValidFrom". |
Data.ValidTo |
target.resource.attribute.labels |
Se agregó como una etiqueta con la clave "ValidTo". |
DewPoint |
additional.fields |
Se agregó como un campo adicional con la clave "DewPoint". |
Details |
metadata.description |
Se asigna directamente a metadata.description . |
Humidity |
additional.fields |
Se agregó como un campo adicional con la clave "Humedad". |
Icon |
additional.fields |
Se agregó como un campo adicional con la clave "Icon". |
Id |
metadata.product_log_id |
Se asigna directamente a metadata.product_log_id . |
IpAddress |
principal.ip |
Se asigna directamente a principal.ip . |
MoonPhase |
additional.fields |
Se agregó como un campo adicional con la clave "MoonPhase". |
Moonrise |
additional.fields |
Se agregó como un campo adicional con la clave "Moonrise". |
Moonset |
additional.fields |
Se agregó como un campo adicional con la clave "Moonset". |
OperationName |
metadata.product_event_type |
Se asigna directamente a metadata.product_event_type . |
Precipitation |
additional.fields |
Se agregó como un campo adicional con la clave "Precipitation". |
Pressure |
additional.fields |
Se agregó como un campo adicional con la clave "Pressure". |
ProjectId |
target.resource_ancestors.product_object_id |
Se usa para completar el campo product_object_id dentro de target.resource_ancestors cuando el elemento superior es de tipo CLOUD_PROJECT . |
ProjectName |
target.resource_ancestors.name , target.resource.attribute.labels |
Se usa para completar el campo name dentro de target.resource_ancestors cuando el elemento superior es de tipo CLOUD_PROJECT . También se agregó como etiqueta a target.resource.attribute.labels con la clave "ProjectName". |
RoleLocation |
target.location.name |
Se asigna directamente a target.location.name . |
ScopeDisplayName |
target.resource_ancestors.name |
Se usa para completar el campo name dentro de target.resource_ancestors cuando el elemento superior es de tipo CLOUD_ORGANIZATION . |
ScopeId |
target.resource_ancestors.product_object_id |
Se usa para completar el campo product_object_id dentro de target.resource_ancestors cuando el elemento superior es de tipo CLOUD_ORGANIZATION . |
ScopeType |
additional.fields |
Se agregó como un campo adicional con la clave "ScopeType". |
Sunrise |
additional.fields |
Se agregó como un campo adicional con la clave "Sunrise". |
Sunset |
additional.fields |
Se agregó como un campo adicional con la clave "Sunset". |
Temperature |
additional.fields |
Se agregó como un campo adicional con la clave "Temperature". |
TenantId |
metadata.product_deployment_id , additional.fields |
Se asigna directamente a metadata.product_deployment_id . También se agregó como un campo adicional con la clave "TenantId". |
TimeGenerated |
metadata.event_timestamp |
Se analizó y se asignó a metadata.event_timestamp . |
UserAgent |
network.http.user_agent , network.http.parsed_user_agent |
Se asigna directamente a network.http.user_agent . También se analiza y se asigna a network.http.parsed_user_agent . |
UVIndex |
additional.fields |
Se agregó como un campo adicional con la clave "UVIndex". |
Visibility |
additional.fields |
Se agregó como un campo adicional con la clave "Visibilidad". |
WindDirection |
additional.fields |
Se agregó como un campo adicional con la clave "WindDirection". |
WindSpeed |
additional.fields |
Se agregó como un campo adicional con la clave "WindSpeed". |
_Internal_WorkspaceResourceId |
additional.fields |
Se agregó como un campo adicional con la clave "workspace_resource_id". |
N/A | metadata.event_type |
Se determina según la lógica basada en OperationName y otros campos. El valor predeterminado es "GENERIC_EVENT" si no coincide con ningún tipo de evento específico. Los valores posibles incluyen "STATUS_SHUTDOWN", "RESOURCE_CREATION", "STATUS_UPDATE", "USER_RESOURCE_DELETION", "RESOURCE_READ", "RESOURCE_WRITTEN", "RESOURCE_DELETION" y "GROUP_MODIFICATION". |
N/A | metadata.vendor_name |
Se establece en "Microsoft". |
N/A | metadata.product_name |
Se debe establecer en "Azure DevOps". |
N/A | metadata.log_type |
Se debe establecer en "AZURE_DEVOPS". |
N/A | principal.user.account_type |
Se establece en "SERVICE_ACCOUNT_TYPE" si AuthenticationMechanism contiene "ServicePrincipal". De lo contrario, se establece en "CLOUD_ACCOUNT_TYPE". |
N/A | target.asset.attribute.cloud.environment |
Se define en MICROSOFT_AZURE . |
N/A | security_result.action |
Se establece en "ALLOW" para las operaciones exitosas (Succeeded, Created, Modified, executed, updated, removed) y en "BLOCK" para las operaciones fallidas (Failed, TimedOut). |
N/A | extensions.auth.mechanism |
Se establece en "USERNAME_PASSWORD" si summary es "UserAuthToken". |
N/A | target.resource.resource_type |
Se establece en "SETTING" si pipeline_id está presente, en "CREDENTIAL" si authorization_id está presente, en "DEVICE" si agent_id está presente o en "DATABASE" si namespace_id está presente. De lo contrario, en algunos casos, se establece como "STORAGE_BUCKET" según operationName . |
N/A | target.resource.resource_subtype |
Se establece en "Canalización" si pipeline_id está presente, en "Token" si authorization_id está presente, en "Agente" si agent_id está presente o en "Espacio de nombres" si namespace_id está presente. |
¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.