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 del SIEM > Feeds > Agregar nuevo
- Centro de contenido > Paquetes de contenido > Comenzar
Cómo configurar el feed de auditoría de Azure DevOps
- Haz clic en el paquete Azure Platform.
- Ubica el tipo de registro Auditoría de Azure DevOps y haz clic en Agregar feed nuevo.
Especifica valores para los siguientes campos:
- Tipo de fuente: Microsoft Azure Blob Storage V2
- URI de Azure: Es la URL del extremo del blob.
ENDPOINT_URL/BLOB_NAME
- Reemplaza lo siguiente:
ENDPOINT_URL
: URL del extremo del blob (https://<storageaccountname>.blob.core.windows.net
)BLOB_NAME
: Es el nombre del blob (por ejemplo,insights-logs-<logname>
).
- Reemplaza lo siguiente:
Opciones de eliminación de la fuente: Selecciona la opción de eliminación según tus preferencias de transferencia.
Antigüedad máxima del archivo: Incluye los archivos modificados en la cantidad de días más reciente. El valor predeterminado es de 180 días.
Clave compartida: Es la clave compartida (una cadena aleatoria de 512 bits en codificación base64) que se usa para acceder a los recursos de Azure.
Opciones avanzadas
- Nombre del feed: Es un valor completado previamente que identifica el feed.
- 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 Crear feed.
Para obtener más información sobre cómo configurar varios feeds para diferentes tipos de registros dentro de esta familia de productos, consulta Configura feeds por producto.
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 de 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 en 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: 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.