Coletar registros de auditoria do Azure DevOps
Visão geral
Esse analisador processa registros de auditoria do Azure DevOps no formato JSON. Ele extrai campos de estruturas JSON aninhadas e de nível superior, mapeando-os para o UDM. A lógica condicional baseada em valores de campo específicos categoriza eventos e enriquece a saída com informações de segurança relevantes. O analisador também processa mensagens não formatadas em JSON tentando extrair um payload JSON usando padrões grok.
Antes de começar
Verifique se você atende aos seguintes pré-requisitos:
- Instância do Google SecOps
- Uma organização ativa do Azure DevOps
- Acesso privilegiado à organização do Azure DevOps e ao Azure
Configurar feeds
Há dois pontos de entrada diferentes para configurar feeds na plataforma do Google SecOps:
- Configurações do SIEM > Feeds
- Central de conteúdo > Pacotes de conteúdo
Configure feeds em Configurações do SIEM > Feeds
Para configurar vários feeds para diferentes tipos de registros nessa família de produtos, consulte Configurar feeds por produto.
Para configurar um único feed, siga estas etapas:
- Acesse Configurações do SIEM > Feeds.
- Clique em Adicionar novo feed.
- Na próxima página, clique em Configurar um único feed.
- No campo Nome do feed, insira um nome para o feed (por exemplo, Registros do Azure DevOps).
- Selecione Webhook como o Tipo de origem.
- Selecione Auditoria do Azure DevOps como o Tipo de registro.
- Clique em Próxima.
- Opcional: especifique valores para os seguintes parâmetros de entrada:
- Delimitador de divisão: o delimitador usado para separar linhas de registro, como
\n
. - Namespace do recurso: o namespace do recurso.
- Rótulos de ingestão: o rótulo aplicado aos eventos deste feed.
- Delimitador de divisão: o delimitador usado para separar linhas de registro, como
- Clique em Próxima.
- Revise a configuração do feed na tela Finalizar e clique em Enviar.
- Clique em Gerar chave secreta para autenticar o feed.
- Copie e armazene a chave secreta. Não é possível ver essa chave secreta novamente. Se necessário, você pode gerar uma nova chave secreta, mas isso torna a anterior obsoleta.
- Na guia Detalhes, copie o URL do endpoint do feed no campo Informações do endpoint. É necessário especificar esse URL de endpoint no aplicativo cliente.
- Clique em Concluído.
Configurar feeds na Central de conteúdo
Especifique valores para os seguintes campos:
- Delimitador de divisão: o delimitador usado para separar linhas de registro, como
\n
.
Opções avançadas
- Nome do feed: um valor pré-preenchido que identifica o feed.
- Tipo de origem: método usado para coletar registros no Google SecOps.
- Namespace do recurso: o namespace do recurso.
- Rótulos de ingestão: o rótulo aplicado aos eventos deste feed.
- Clique em Próxima.
- Revise a configuração do feed na tela Finalizar e clique em Enviar.
- Clique em Gerar chave secreta para autenticar o feed.
Criar uma chave de API para o feed de webhook
Acesse console doGoogle Cloud > Credenciais.
Clique em Criar credenciais e, em seguida, selecione Chave de API.
Restrinja o acesso da chave de API à API Google Security Operations.
Especifique o URL do endpoint
- No aplicativo cliente, especifique o URL do endpoint HTTPS fornecido no feed do webhook.
Ative a autenticação especificando a chave de API e a chave secreta como parte do cabeçalho personalizado no seguinte formato:
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
Recomendação: especifique a chave de API como um cabeçalho em vez de no URL. Se o cliente de webhook não aceitar cabeçalhos personalizados, especifique a chave de API e a chave secreta usando parâmetros de consulta no seguinte formato:
ENDPOINT_URL?key=API_KEY&secret=SECRET
Substitua:
ENDPOINT_URL
: o URL do endpoint do feed.API_KEY
: a chave de API para autenticar no Google Security Operations.SECRET
: a chave secreta gerada para autenticar o feed.
Configurar o recurso de auditoria no Azure DevOps
- Faça login na sua organização (
https://dev.azure.com/{yourorganization}
). - Selecione o ícone de engrenagem para Configurações da organização.
- Selecione Políticas em Segurança.
- Defina o botão Registrar eventos de auditoria como ATIVADO.
Configurar um tópico do Event Grid no Azure
- Faça login no portal do Azure.
- Pesquise e acesse a Grade de Eventos.
- Localize Tópicos em Eventos personalizados.
- Clique em + Criar.
- Selecione sua Assinatura e o Grupo de recursos. Forneça um nome (por exemplo,
DevopsAuditLog
) e selecione a região. Clique em Revisar e criar. - Acesse o novo Tópico e copie o URL do endpoint do tópico.
- Acesse Configurações > Chaves de acesso e copie a Chave 1.
Configurar o fluxo de registros do Azure DevOps para o Event Grid
- Faça login na sua organização (
https://dev.azure.com/{yourorganization}
). - Selecione o ícone de engrenagem para Configurações da organização.
- Selecione Auditoria.
- Acesse a guia Streams e selecione New stream > Event Grid.
- Insira o endpoint do tópico e a chave de acesso criados em Configurar um tópico do Event Grid no Azure.
Configurar um webhook no Azure DevOps para o Google SecOps
- No portal do Azure, pesquise e acesse Event Grid.
- Selecione o Tópico criado anteriormente.
- Acesse Entidades > Assinatura de evento.
- Clique em + Assinatura de evento.
- Forneça um nome descritivo (por exemplo, *
Google SecOps Integration
). - Selecione Web Hook e clique em Configurar um endpoint.
- Configure o endpoint:
- Endpoint do assinante: insira o URL do endpoint de API Google SecOps.
- Na seção Cabeçalhos HTTP, adicione os seguintes cabeçalhos:
- Header 1:
- Chave:
X-goog-api-key
- Valor: a chave de API que você criou na seção Criar uma chave de API para o feed de webhook.
- Chave:
- Header 2:
- Chave:
X-Webhook-Access-Key
- Valor: a chave secreta gerada na seção Configurar um feed no Google SecOps para ingerir os registros do Azure DevOps.
- Chave:
- Header 1:
- Defina o cabeçalho Content-Type como
application/json
.
- Clique em Criar.
Tabela de mapeamento do UDM
Campo de registro | Mapeamento do UDM | Lógica |
---|---|---|
ActivityId |
metadata.product_log_id |
Mapeado diretamente do campo Id no registro bruto quando o campo records não está presente ou do campo ActivityId no objeto data quando records está presente. |
ActionId |
metadata.product_event_type |
Mapeado diretamente do campo ActionId no objeto data . |
ActorCUID |
additional.fields |
Incluído como um campo adicional com a chave "Actor CUID". |
ActorDisplayName |
principal.user.user_display_name |
Mapeado diretamente do campo ActorDisplayName se não for "Serviço do Azure DevOps". Se for "Serviço do Azure DevOps", ele será adicionado como um rótulo a principal.resource.attribute.labels . |
ActorUPN |
principal.user.email_addresses |
Mapeado diretamente do campo ActorUPN se corresponder a um padrão de endereço de e-mail. |
ActorUserId |
principal.user.userid |
Mapeado diretamente do campo ActorUserId . |
Area |
target.application |
Usado para criar o campo target.application adicionando "DevOps " antes do valor Area . |
AuthenticationMechanism |
extensions.auth.auth_details , security_result.rule_id |
Analisado para extrair detalhes de autenticação e ID da regra. Os detalhes de autenticação são mapeados para extensions.auth.auth_details . O ID da regra extraída é mapeado para security_result.rule_id . |
CategoryDisplayName |
security_result.action_details |
Mapeado diretamente para security_result.action_details . |
City |
principal.location.city |
Mapeado diretamente do campo City . |
Conditions |
additional.fields |
Adicionado como um campo extra com a chave "Condições". |
Country |
principal.location.country_or_region |
Mapeado diretamente do campo Country . |
Data.* |
Vários | Os campos no objeto Data são mapeados para diferentes campos da UDM com base nos nomes e no contexto deles. Confira exemplos específicos abaixo. |
Data.AccessLevel |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "AccessLevel". |
Data.AgentId |
target.resource.product_object_id |
Mapeado para target.resource.product_object_id se PipelineId e AuthorizationId não estiverem presentes. |
Data.AgentName |
target.resource.name |
Mapeado para target.resource.name se PipelineName , NamespaceName e DisplayName não estiverem presentes. |
Data.AuthorizationId |
target.resource.product_object_id |
Mapeado para target.resource.product_object_id se PipelineId não estiver presente. |
Data.CallerProcedure |
additional.fields |
Adicionado como um campo extra com a chave "CallerProcedure". |
Data.CheckSuiteId |
additional.fields |
Adicionado como um campo extra com a chave "CheckSuiteId". |
Data.CheckSuiteStatus |
additional.fields |
Adicionado como um campo extra com a chave "CheckSuiteStatus". |
Data.ConnectionId |
additional.fields |
Adicionado como um campo extra com a chave "ConnectionId". |
Data.ConnectionName |
additional.fields |
Adicionado como um campo extra com a chave "ConnectionName". |
Data.ConnectionType |
additional.fields |
Adicionado como um campo extra com a chave "ConnectionType". |
Data.DefinitionId |
additional.fields |
Adicionado como um campo extra com a chave "DefinitionId". |
Data.DeploymentResult |
additional.fields |
Adicionado como um campo extra com a chave "DeploymentResult". |
Data.DisplayName |
target.resource.name |
Mapeado para target.resource.name se PipelineName e NamespaceName não estiverem presentes. |
Data.EndpointIdList |
additional.fields |
Adicionado como um campo extra com a chave "EndpointIdList". |
Data.EnvironmentName |
additional.fields |
Adicionado como um campo extra com a chave "EnvironmentName". |
Data.Filter.continuationToken |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "continuation_token". |
Data.Filter.endTime |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "filter_end_time". |
Data.Filter.startTime |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "filter_start_time". |
Data.FinishTime |
additional.fields |
Adicionado como um campo extra com a chave "FinishTime". |
Data.GroupId |
target.group.product_object_id |
Mapeado diretamente para target.group.product_object_id quando Data.Updates.0.GroupId não está presente. |
Data.GroupName |
target.group.group_display_name |
Mapeado diretamente para target.group.group_display_name . |
Data.JobName |
additional.fields |
Adicionado como um campo extra com a chave "JobName". |
Data.MemberId |
target.user.userid |
Mapeado diretamente para target.user.userid quando Data.Updates.0.MemberId não está presente. |
Data.MemberDisplayName |
target.user.user_display_name |
Mapeado diretamente para target.user.user_display_name . |
Data.NamespaceId |
target.resource.product_object_id |
Mapeado para target.resource.product_object_id se PipelineId , AuthorizationId e AgentId não estiverem presentes. |
Data.NamespaceName |
target.resource.name |
Mapeado para target.resource.name se PipelineName não estiver presente. |
Data.ownerDetails |
additional.fields |
Adicionado como um campo extra com a chave "OwnerDetails". |
Data.OwnerId |
additional.fields |
Adicionado como um campo extra com a chave "OwnerId". |
Data.PipelineId |
target.resource.product_object_id |
Mapeado diretamente para target.resource.product_object_id . |
Data.PipelineName |
target.resource.name |
Mapeado diretamente para target.resource.name . |
Data.PipelineRevision |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "PipelineRevision". |
Data.PipelineScope |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "PipelineScope". |
Data.PlanType |
additional.fields |
Adicionado como um campo extra com a chave "PlanType". |
Data.PreviousAccessLevel |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "PreviousAccessLevel". |
Data.PublisherName |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "PublisherName". |
Data.Reason |
additional.fields |
Adicionado como um campo extra com a chave "Reason". |
Data.ReleaseId |
additional.fields |
Adicionado como um campo extra com a chave "ReleaseId". |
Data.ReleaseName |
additional.fields |
Adicionado como um campo extra com a chave "ReleaseName". |
Data.RequesterId |
additional.fields |
Adicionado como um campo extra com a chave "RequesterId". |
Data.RetentionLeaseId |
additional.fields |
Adicionado como um campo extra com a chave "RetentionLeaseId". |
Data.RetentionOwnerId |
additional.fields |
Adicionado como um campo extra com a chave "RetentionOwnerId". |
Data.RunName |
additional.fields |
Adicionado como um campo extra com a chave "RunName". |
Data.Scopes |
target.resource.attribute.labels |
Adicionadas como rótulos com a chave "Scope". |
Data.StageName |
additional.fields |
Adicionado como um campo extra com a chave "StageName". |
Data.StartTime |
additional.fields |
Adicionado como um campo extra com a chave "StartTime". |
Data.TargetUser |
target.user.userid |
Mapeado diretamente para target.user.userid . |
Data.Timestamp |
metadata.event_timestamp |
Analisado e mapeado para metadata.event_timestamp . |
Data.TokenType |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "TokenType". |
Data.Updates.0.GroupId |
target.group.product_object_id |
Mapeado diretamente para target.group.product_object_id . |
Data.Updates.0.MemberId |
target.user.userid |
Mapeado diretamente para target.user.userid . |
Data.ValidFrom |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "ValidFrom". |
Data.ValidTo |
target.resource.attribute.labels |
Adicionado como um rótulo com a chave "ValidTo". |
DewPoint |
additional.fields |
Adicionado como um campo extra com a chave "DewPoint". |
Details |
metadata.description |
Mapeado diretamente para metadata.description . |
Humidity |
additional.fields |
Adicionado como um campo extra com a chave "Humidity". |
Icon |
additional.fields |
Adicionado como um campo extra com a chave "Icon". |
Id |
metadata.product_log_id |
Mapeado diretamente para metadata.product_log_id . |
IpAddress |
principal.ip |
Mapeado diretamente para principal.ip . |
MoonPhase |
additional.fields |
Adicionado como um campo extra com a chave "MoonPhase". |
Moonrise |
additional.fields |
Adicionado como um campo extra com a chave "Moonrise". |
Moonset |
additional.fields |
Adicionado como um campo extra com a chave "Moonset". |
OperationName |
metadata.product_event_type |
Mapeado diretamente para metadata.product_event_type . |
Precipitation |
additional.fields |
Adicionado como um campo extra com a chave "Precipitação". |
Pressure |
additional.fields |
Adicionado como um campo extra com a chave "Pressure". |
ProjectId |
target.resource_ancestors.product_object_id |
Usado para preencher o campo product_object_id em target.resource_ancestors quando o ancestral é do tipo CLOUD_PROJECT . |
ProjectName |
target.resource_ancestors.name , target.resource.attribute.labels |
Usado para preencher o campo name em target.resource_ancestors quando o ancestral é do tipo CLOUD_PROJECT . Também adicionado como um rótulo a target.resource.attribute.labels com a chave "ProjectName". |
RoleLocation |
target.location.name |
Mapeado diretamente para target.location.name . |
ScopeDisplayName |
target.resource_ancestors.name |
Usado para preencher o campo name em target.resource_ancestors quando o ancestral é do tipo CLOUD_ORGANIZATION . |
ScopeId |
target.resource_ancestors.product_object_id |
Usado para preencher o campo product_object_id em target.resource_ancestors quando o ancestral é do tipo CLOUD_ORGANIZATION . |
ScopeType |
additional.fields |
Adicionado como um campo extra com a chave "ScopeType". |
Sunrise |
additional.fields |
Adicionado como um campo extra com a chave "Sunrise". |
Sunset |
additional.fields |
Adicionado como um campo extra com a chave "Sunset". |
Temperature |
additional.fields |
Adicionado como um campo extra com a chave "Temperatura". |
TenantId |
metadata.product_deployment_id , additional.fields |
Mapeado diretamente para metadata.product_deployment_id . Também adicionado como um campo extra com a chave "TenantId". |
TimeGenerated |
metadata.event_timestamp |
Analisado e mapeado para metadata.event_timestamp . |
UserAgent |
network.http.user_agent , network.http.parsed_user_agent |
Mapeado diretamente para network.http.user_agent . Também analisado e mapeado para network.http.parsed_user_agent . |
UVIndex |
additional.fields |
Adicionado como um campo extra com a chave "UVIndex". |
Visibility |
additional.fields |
Adicionado como um campo extra com a chave "Visibility". |
WindDirection |
additional.fields |
Adicionado como um campo extra com a chave "WindDirection". |
WindSpeed |
additional.fields |
Adicionado como um campo extra com a chave "WindSpeed". |
_Internal_WorkspaceResourceId |
additional.fields |
Adicionado como um campo extra com a chave "workspace_resource_id". |
N/A | metadata.event_type |
Determinado por uma lógica baseada no OperationName e em outros campos. O padrão é "GENERIC_EVENT" se nenhum tipo de evento específico for correspondente. Os valores possíveis incluem "STATUS_SHUTDOWN", "RESOURCE_CREATION", "STATUS_UPDATE", "USER_RESOURCE_DELETION", "RESOURCE_READ", "RESOURCE_WRITTEN", "RESOURCE_DELETION" e "GROUP_MODIFICATION". |
N/A | metadata.vendor_name |
Defina como "Microsoft". |
N/A | metadata.product_name |
Defina como "Azure DevOps". |
N/A | metadata.log_type |
Defina como "AZURE_DEVOPS". |
N/A | principal.user.account_type |
Defina como "SERVICE_ACCOUNT_TYPE" se AuthenticationMechanism contiver "ServicePrincipal". Caso contrário, defina como "CLOUD_ACCOUNT_TYPE". |
N/A | target.asset.attribute.cloud.environment |
Defina como MICROSOFT_AZURE . |
N/A | security_result.action |
Definido como "ALLOW" para operações bem-sucedidas (Succeeded, Created, Modified, executed, updated, removed) e "BLOCK" para operações com falha (Failed, TimedOut). |
N/A | extensions.auth.mechanism |
Definido como "USERNAME_PASSWORD" se summary for "UserAuthToken". |
N/A | target.resource.resource_type |
Definido como "SETTING" se pipeline_id estiver presente, "CREDENTIAL" se authorization_id estiver presente, "DEVICE" se agent_id estiver presente ou "DATABASE" se namespace_id estiver presente. Caso contrário, será definido como "STORAGE_BUCKET" em alguns casos com base em operationName . |
N/A | target.resource.resource_subtype |
Definido como "Pipeline" se pipeline_id estiver presente, "Token" se authorization_id estiver presente, "Agent" se agent_id estiver presente ou "Namespace" se namespace_id estiver presente. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.