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 a la UDM. La lógica condicional basada en valores de campos específicos clasifica los eventos y enriquece el resultado con información de seguridad relevante. El analizador también controla los mensajes con formato que no son JSON, ya que intenta extraer una carga útil JSON con patrones de grok.
Antes de comenzar
- Asegúrate de tener una instancia de Google SecOps.
- Asegúrate de tener una organización de Azure DevOps activa.
- Asegúrate de tener acceso con privilegios a la organización de Azure DevOps y a Azure.
Configura un feed en Google SecOps para transferir los registros de Azure DevOps
- Ve a Configuración de SIEM > Feeds.
- Haz clic en Agregar nueva.
- 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 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 de recursos: Es el espacio de nombres de recursos.
- 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 Generate Secret Key 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 volver a generar 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.
Crea una clave de API para el feed de webhook
Ve a consola de Google Cloud > 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.
Habilita la autenticación especificando 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 consulta 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 acceder a la Configuración de la organización.
- Selecciona Políticas en Seguridad.
- 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.
- Busca Temas en Eventos personalizados.
- 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 > Llaves de acceso y copia la Clave 1.
Configura la transmisión de registros de Azure DevOps a Event Grid
- Accede a tu organización (
https://dev.azure.com/{yourorganization}
). - Selecciona el ícono de ajustes para acceder a la Configuración de la organización.
- Selecciona Auditoría.
- Ve a la pestaña Transmisiones y selecciona Nueva transmisión > Cuadrícula de eventos.
- Ingresa el extremo del tema y la clave de acceso que creaste en Cómo configurar 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 que creaste anteriormente.
- Ve a Entidades > Suscripción a eventos.
- Haz clic en + Suscripción a eventos.
- Proporciona un nombre descriptivo (p. ej., Integración de Google SecOps).
- Selecciona Webhook y haz clic en Configurar un extremo.
- Configura el extremo:
- Extremo del suscriptor: Ingresa la URL del extremo de API de Google SecOps.
- Agrega
?key=<API_KEY>&secret=<SECRET_KEY>
a la URL de la carga útil. - Establece el encabezado Content-Type en 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 asignan directamente desde el campo Id en el registro sin procesar cuando no está presente el campo records , 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 “Servicio de Azure DevOps”, 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 agregando "DevOps " al principio del valor 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 la regla extraída se asigna a security_result.rule_id . |
CategoryDisplayName |
security_result.action_details |
Se asignan 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 "Condiciones". |
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 de la AUA según sus nombres y contexto. Consulta los ejemplos específicos que aparecen 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 asignan 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 asignan 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 asignan directamente a target.resource.product_object_id . |
Data.PipelineName |
target.resource.name |
Se asignan 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 "Motivo". |
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 agregaron como etiquetas con la clave "Alcance". |
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 asignan directamente a target.user.userid . |
Data.Timestamp |
metadata.event_timestamp |
Se analiza y se asigna 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 asignan directamente a target.group.product_object_id . |
Data.Updates.0.MemberId |
target.user.userid |
Se asignan 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 etiqueta con la clave "ValidTo". |
DewPoint |
additional.fields |
Se agregó como un campo adicional con la clave "DewPoint". |
Details |
metadata.description |
Se asignan directamente a metadata.description . |
Humidity |
additional.fields |
Se agregó como un campo adicional con la clave "Humidity". |
Icon |
additional.fields |
Se agregó como un campo adicional con la clave "Icon". |
Id |
metadata.product_log_id |
Se asignan directamente a metadata.product_log_id . |
IpAddress |
principal.ip |
Se asignan 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 "Amanecer lunar". |
Moonset |
additional.fields |
Se agregó como un campo adicional con la clave "Puesta de la luna". |
OperationName |
metadata.product_event_type |
Se asignan directamente a metadata.product_event_type . |
Precipitation |
additional.fields |
Se agregó como un campo adicional con la clave "Precipitación". |
Pressure |
additional.fields |
Se agregó como un campo adicional con la clave "Presión". |
ProjectId |
target.resource_ancestors.product_object_id |
Se usa para propagar el campo product_object_id dentro de target.resource_ancestors cuando el ancestro es de tipo CLOUD_PROJECT . |
ProjectName |
target.resource_ancestors.name , target.resource.attribute.labels |
Se usa para propagar el campo name dentro de target.resource_ancestors cuando el ancestro 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 asignan directamente a target.location.name . |
ScopeDisplayName |
target.resource_ancestors.name |
Se usa para propagar el campo name dentro de target.resource_ancestors cuando el ancestro es de tipo CLOUD_ORGANIZATION . |
ScopeId |
target.resource_ancestors.product_object_id |
Se usa para propagar el campo product_object_id dentro de target.resource_ancestors cuando el ancestro 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 "Amanecer". |
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 asignan directamente a metadata.product_deployment_id . También se agregó como un campo adicional con la clave "TenantId". |
TimeGenerated |
metadata.event_timestamp |
Se analiza y se asigna a metadata.event_timestamp . |
UserAgent |
network.http.user_agent , network.http.parsed_user_agent |
Se asignan 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 mediante una lógica basada en OperationName y otros campos. El valor predeterminado es "GENERIC_EVENT" si no se encuentra ningún tipo de evento específico. Los valores posibles son "STATUS_SHUTDOWN", "RESOURCE_CREATION", "STATUS_UPDATE", "USER_RESOURCE_DELETION", "RESOURCE_READ", "RESOURCE_WRITTEN", "RESOURCE_DELETION" y "GROUP_MODIFICATION". |
N/A | metadata.vendor_name |
Establece el valor en “Microsoft”. |
N/A | metadata.product_name |
Establece la opción en "Azure DevOps". |
N/A | metadata.log_type |
Establece el valor en "AZURE_DEVOPS". |
N/A | principal.user.account_type |
Establece en "SERVICE_ACCOUNT_TYPE" si AuthenticationMechanism contiene "ServicePrincipal"; de lo contrario, configúralo en "CLOUD_ACCOUNT_TYPE". |
N/A | target.asset.attribute.cloud.environment |
Se define en MICROSOFT_AZURE . |
N/A | security_result.action |
Establece el valor en "ALLOW" para las operaciones que se realizan correctamente (Succeeded, Created, Modified, executed, updated, removed) y en "BLOCK" para las operaciones que fallan (Failed, TimedOut). |
N/A | extensions.auth.mechanism |
Establece en "USERNAME_PASSWORD" si summary es "UserAuthToken". |
N/A | target.resource.resource_type |
Se establece en "SETTING" si pipeline_id está presente, "CREDENTIAL" si authorization_id está presente, "DEVICE" si agent_id está presente o "DATABASE" si namespace_id está presente. De lo contrario, se establece como "STORAGE_BUCKET" en algunos casos 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. |
Cambios
2024-01-19
- Se cambió el valor de "metadata.eventtype" de "SERVICE*" a "USER_RESOURCE_UPDATE_CONTENT" si están presentes los datos del usuario principal y los datos del recurso de destino.
- Se cambió la asignación de "IpAddress" de "target.ip" a "principal.ip".
- Se cambió la asignación de "ActorCUID" de "principal.user.product_object_id" a "additional.fields".
- Se cambió la asignación de "ScopeId" de "principal.asset_id" a "resource_ancestors.product_object_id".
- Se cambió la asignación de "_Internal_WorkspaceResourceId" de "target.resource.product_object_id" a "additional.fields".
- Se cambió la asignación de "ProjectId" de "target.resource.attribute.labels" a "target.resource_ancestors.product_object_id".
- Se cambió la asignación de "AuthenticationMechanism" de "security_result.summary" a "extensions.auth.auth_details".
- Se cambió la asignación de "CorrelationId" de "network.session_id" a "additional.fields".
- Se cambió la asignación de "ScopeDisplayName" de "additional.fields" a "target.resource_ancestors.name".
- Se cambió la asignación de "PipelineId" de "additional.fields" a "target.resource.product_object_id".
- Se cambió la asignación de "PipelineName" de "additional.fields" a "target.resource.name".
- Se cambió la asignación de "PipelineScope" de "additional.fields" a "target.resource.attribute.labels".
- Se cambió la asignación de "PipelineRevision" de "additional.fields" a "target.resource.attribute.labels".
- Se cambió la asignación de "ProjectId" de "target.resource.resource.attribute.labels" a "target.resource_ancestors.product_object_id".
- Se cambió la asignación de "Area" de "additional.fields" a "target.application".
- Se asignó el valor "MICROSOFT_AZURE" a "target.asset.attribute.cloud.environment".
- Cuando "AuthenticationMechanism" tenga el valor "ServicePrincipal", establece "SERVICE_ACCOUNT_TYPE" en "principal.user.account_type". De lo contrario, establece "CLOUD_ACCOUNT_TYPE" en "principal.user.account_type".
- Se asignó "Category" a "security_result.action_details".
- Se asignó “ALLOW” o “BLOCK” a “security_result.action” según el campo “Details”.
- Se asignó "ActivityId" a "additional.fields".
2024-01-09
- Se agregaron Grok y gsub para analizar los registros JSON sin analizar.
- Se asignaron "rec.correlationId", "properties.currentHealthStatus", "properties.previousHealthStatus", "properties.type", "properties.cause", "properties.title", "properties.details", "properties.recommendationType", "properties.recommendationCategory", "properties.recommendationImpact", "properties.recommendationName", "properties.recommendationResourceLink", "properties.recommendationSchemaVersion", "properties.eventCategory", "properties.hierarchy", "properties.message", "properties.entity", "identity.claims.xms.tcdt", "identity.claims.aio", "identity.claims.appid", "identity.claims.appidacr", "identity.claims.aud", "identity.claims.exp", "identity.claims.iat", "identity.claims.idtyp", "identity.claims.iss", "identity.claims.uti", "identity.claims.rh", "identity.claims.ver", "identity.claims.nbf", "identity.authorization.evidence.roleAssignmentId", "identity.authorization.evidence.principalType", "identity.authorization.evidence.principalId", "identity.authorization.evidence.roleAssignmentScope", "identity.authorization.evidence.roleDefinitionId" a "security_result.detection_fields".
- Se asignaron "resultSignature.label", "rec.resultType", "Visibility", "Humidity", "Precipitation","MoonPhase", "Moonrise", "Moonset", "Pressure", "WindSpeed", "UVIndex", "DewPoint", "WindDirection", "Sunrise", "Sunset", "Temperature", "Icon", "Conditions" a "additional.fields".
- Se asignó "level" a "security_result.severity".
- Se asignó "appname" a "target.application".
- Se asignó "category.details" a "security.result.category.details".
- Se asignó "rec.resourceId" a "target.resource.id".
- Se asignó "res.extensionResourceName" a "principal.hostname".
2023-11-23
- Se agregó compatibilidad con un nuevo patrón de registros JSON.
- Se asignó "data.TimeGenerated" a "metadata.event_timestamp".
- Cuando falta "_Internal_WorkspaceResourceId", se asigna "topic" a "target.resource.product_object_id".
- Se asignó "data.Data.ConnectionId" a "additional.fields".
- Se asignó "data.Data.ownerDetails" a "additional.fields".
- Se asignó "data.Data.DeploymentResult" a "additional.fields".
- Se asignó "data.Data.EnvironmentName" a "additional.fields".
- Se asignó "data.Data.JobName" a "additional.fields".
- Se asignó "data.Data.StageName" a "additional.fields".
- Se asignó "data.Data.RunName" a "additional.fields".
- Se asignó "data.Data.RetentionLeaseId" a "additional.fields".
- Se asignó "data.Data.CheckSuiteId" a "additional.fields".
- Se asignó "data.Data.CheckSuiteStatus" a "additional.fields".
- Se asignó "data.Data.ApprovalRequest" a "additional.fields".
- Se asignó "data.Data.ApprovalType" a "additional.fields".
- Se asignó "subject" a "additional.fields".
- Se asignó "data.ActorUserId" a "principal.user.userid".
- Se asignó "data.ActorDisplayName" a "principal.user.user_display_name".
- Se asignó "data.ActorCUID" a "principal.user.product_object_id".
- Se asignó "data.ActorUPN" a "principal.user.email_addresses".
- Se asignó "data.ScopeId" a "principal.asset_id".
- Se asignó "data.CorrelationId" a "network.session_id".
- Se asignó "data.UserAgent" a "network.http.user_agent".
- Se asignó "data.ProjectId" a "target.resource.attribute.labels".
- Se asignó "data.ScopeType" a "additional.fields".
- Se asignó "data.ProjectName" a "target.resource.attribute.labels".
- Se asignó "data.Details" a "metadata.description".
- Se asignó "data.CategoryDisplayName" a "security_result.rule_name".
- Se asignó "data.Area" a "additional.fields".
- Se asignó "data.Id" a "metadata.product_log_id".
- Se asignó "data.ActionId" a "metadata.product_event_type".
- Se asignó "data.Timestamp" a "metadata.event_timestamp".
2022-06-28
- Analizador creado recientemente