Raccogliere gli audit log di Azure DevOps
Panoramica
Questo parser gestisce i log di controllo di Azure DevOps in formato JSON. Estrae i campi dalle strutture JSON nidificate e di primo livello, mappandoli a UDM. La logica condizionale basata su valori di campi specifici classifica gli eventi e arricchisce l'output con informazioni di sicurezza pertinenti. Il parser gestisce anche i messaggi non in formato JSON tentando di estrarre un payload JSON utilizzando i pattern grok.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Istanza Google SecOps
- Un'organizzazione Azure DevOps attiva
- Accesso con privilegi all'organizzazione Azure DevOps e ad Azure
Configurare i feed
Esistono due diversi punti di accesso per configurare i feed nella piattaforma Google SecOps:
- Impostazioni SIEM > Feed
- Hub dei contenuti > Pacchetti di contenuti
Configurare i feed da Impostazioni SIEM > Feed
Per configurare più feed per diversi tipi di log all'interno di questa famiglia di prodotti, consulta Configurare i feed per prodotto.
Per configurare un singolo feed:
- Vai a Impostazioni SIEM > Feed.
- Fai clic su Aggiungi nuovo feed.
- Nella pagina successiva, fai clic su Configura un singolo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio, Azure Devops Logs).
- Seleziona Webhook come Tipo di origine.
- Seleziona Azure Devops Audit come Tipo di log.
- Fai clic su Avanti.
- (Facoltativo) Specifica i valori per i seguenti parametri di input:
- Delimitatore di suddivisione: il delimitatore utilizzato per separare le righe di log, ad esempio
\n
. - Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
- Etichette di importazione: l'etichetta applicata agli eventi di questo feed.
- Delimitatore di suddivisione: il delimitatore utilizzato per separare le righe di log, ad esempio
- Fai clic su Avanti.
- Controlla la configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
- Fai clic su Genera chiave segreta per generare una chiave segreta per autenticare questo feed.
- Copia e memorizza la chiave segreta. Non puoi visualizzare di nuovo questa chiave segreta. Se necessario, puoi rigenerare una nuova chiave segreta, ma questa azione rende obsoleta la chiave segreta precedente.
- Nella scheda Dettagli, copia l'URL dell'endpoint del feed dal campo Informazioni sull'endpoint. Devi specificare questo URL dell'endpoint nell'applicazione client.
- Fai clic su Fine.
Configurare i feed dall'hub dei contenuti
Specifica i valori per i seguenti campi:
- Delimitatore di suddivisione: il delimitatore utilizzato per separare le righe di log, ad esempio
\n
.
Opzioni avanzate
- Nome feed: un valore precompilato che identifica il feed.
- Tipo di origine: metodo utilizzato per raccogliere i log in Google SecOps.
- Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
- Etichette di importazione: l'etichetta applicata agli eventi di questo feed.
- Fai clic su Avanti.
- Controlla la configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
- Fai clic su Genera chiave segreta per generare una chiave segreta per autenticare questo feed.
Crea una chiave API per il feed webhook
Vai alla console Google Cloud > Credenziali.
Fai clic su Crea credenziali e poi seleziona Chiave API.
Limita l'accesso della chiave API all'API Google Security Operations.
Specifica l'URL dell'endpoint
- Nella tua applicazione client, specifica l'URL dell'endpoint HTTPS fornito nel feed webhook.
Attiva l'autenticazione specificando la chiave API e la chiave segreta come parte dell'intestazione personalizzata nel seguente formato:
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
Consiglio: specifica la chiave API come intestazione anziché nell'URL. Se il client webhook non supporta le intestazioni personalizzate, puoi specificare la chiave API e la chiave segreta utilizzando parametri di ricerca nel seguente formato:
ENDPOINT_URL?key=API_KEY&secret=SECRET
Sostituisci quanto segue:
ENDPOINT_URL
: l'URL dell'endpoint del feed.API_KEY
: la chiave API per l'autenticazione a Google Security Operations.SECRET
: la chiave segreta che hai generato per autenticare il feed.
Configurare la funzionalità di controllo in Azure DevOps
- Accedi alla tua organizzazione (
https://dev.azure.com/{yourorganization}
). - Seleziona l'icona a forma di ingranaggio per Impostazioni dell'organizzazione.
- Seleziona Policy nella sezione Sicurezza.
- Imposta il pulsante Registra eventi di controllo su ON.
Configura un argomento Event Grid in Azure
- Accedi al portale Azure.
- Cerca e accedi a Event Grid.
- Individua Argomenti in Eventi personalizzati.
- Fai clic su + Crea.
- Seleziona l'abbonamento e il gruppo di risorse. Fornisci un nome (ad esempio,
DevopsAuditLog
) e seleziona la regione. Fai clic su Rivedi e crea. - Accedi al nuovo argomento e copia l'URL dell'endpoint dell'argomento.
- Vai a Impostazioni > Chiavi di accesso e copia Chiave 1.
Configurare il flusso di log di Azure DevOps in Event Grid
- Accedi alla tua organizzazione (
https://dev.azure.com/{yourorganization}
). - Seleziona l'icona a forma di ingranaggio per Impostazioni dell'organizzazione.
- Seleziona Controlli.
- Vai alla scheda Stream e seleziona Nuovo stream > Event Grid.
- Inserisci l'endpoint dell'argomento e la chiave di accesso creati in Configurare un argomento Event Grid in Azure.
Configura un webhook in Azure DevOps per Google SecOps
- Nel portale Azure, cerca e accedi a Event Grid.
- Seleziona l'argomento creato in precedenza.
- Vai a Entità > Abbonamento agli eventi.
- Fai clic su + Event Subscription (Abbonamento all'evento).
- Fornisci un nome descrittivo (ad esempio, *
Google SecOps Integration
). - Seleziona Web Hook e fai clic su Configura un endpoint.
- Configura l'endpoint:
- Endpoint abbonato: inserisci l'URL dell'endpoint API Google SecOps.
- Nella sezione Intestazioni HTTP, aggiungi le seguenti intestazioni:
- Header 1:
- Key:
X-goog-api-key
- Valore: la chiave API che hai creato nella sezione Creare una chiave API per il feed webhook.
- Key:
- Header 2:
- Key:
X-Webhook-Access-Key
- Valore: la chiave segreta che hai generato nella sezione Configura un feed in Google SecOps per importare i log di Azure DevOps.
- Key:
- Header 1:
- Imposta l'intestazione Content-Type su
application/json
.
- Fai clic su Crea.
Tabella di mappatura UDM
Campo log | Mappatura UDM | Logic |
---|---|---|
ActivityId |
metadata.product_log_id |
Mappato direttamente dal campo Id nel log non elaborato quando il campo records non è presente o dal campo ActivityId all'interno dell'oggetto data quando records è presente. |
ActionId |
metadata.product_event_type |
Mappato direttamente dal campo ActionId all'interno dell'oggetto data . |
ActorCUID |
additional.fields |
Incluso come campo aggiuntivo con la chiave "Actor CUID". |
ActorDisplayName |
principal.user.user_display_name |
Mappato direttamente dal campo ActorDisplayName se non è "Servizio Azure DevOps". Se è "Azure DevOps Service", viene aggiunto come etichetta a principal.resource.attribute.labels . |
ActorUPN |
principal.user.email_addresses |
Mappato direttamente dal campo ActorUPN se corrisponde a un pattern di indirizzo email. |
ActorUserId |
principal.user.userid |
Mappato direttamente dal campo ActorUserId . |
Area |
target.application |
Utilizzato per creare il campo target.application anteponendo "DevOps " al valore Area . |
AuthenticationMechanism |
extensions.auth.auth_details , security_result.rule_id |
Analizzato per estrarre i dettagli di autenticazione e l'ID regola. I dettagli di autenticazione sono mappati a extensions.auth.auth_details . L'ID regola estratto è mappato a security_result.rule_id . |
CategoryDisplayName |
security_result.action_details |
Mappato direttamente a security_result.action_details . |
City |
principal.location.city |
Mappato direttamente dal campo City . |
Conditions |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Conditions". |
Country |
principal.location.country_or_region |
Mappato direttamente dal campo Country . |
Data.* |
Varie | I campi all'interno dell'oggetto Data vengono mappati a campi UDM diversi in base ai loro nomi e al contesto. Di seguito sono riportati alcuni esempi specifici. |
Data.AccessLevel |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "AccessLevel". |
Data.AgentId |
target.resource.product_object_id |
Mappato a target.resource.product_object_id se PipelineId e AuthorizationId non sono presenti. |
Data.AgentName |
target.resource.name |
Mappato a target.resource.name se PipelineName , NamespaceName e DisplayName non sono presenti. |
Data.AuthorizationId |
target.resource.product_object_id |
Mappato a target.resource.product_object_id se PipelineId non è presente. |
Data.CallerProcedure |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "CallerProcedure". |
Data.CheckSuiteId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "CheckSuiteId". |
Data.CheckSuiteStatus |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "CheckSuiteStatus". |
Data.ConnectionId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ConnectionId". |
Data.ConnectionName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ConnectionName". |
Data.ConnectionType |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ConnectionType". |
Data.DefinitionId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "DefinitionId". |
Data.DeploymentResult |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "DeploymentResult". |
Data.DisplayName |
target.resource.name |
Mappato a target.resource.name se PipelineName e NamespaceName non sono presenti. |
Data.EndpointIdList |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "EndpointIdList". |
Data.EnvironmentName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "EnvironmentName". |
Data.Filter.continuationToken |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "continuation_token". |
Data.Filter.endTime |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "filter_end_time". |
Data.Filter.startTime |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "filter_start_time". |
Data.FinishTime |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "FinishTime". |
Data.GroupId |
target.group.product_object_id |
Mappato direttamente su target.group.product_object_id quando Data.Updates.0.GroupId non è presente. |
Data.GroupName |
target.group.group_display_name |
Mappato direttamente a target.group.group_display_name . |
Data.JobName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "JobName". |
Data.MemberId |
target.user.userid |
Mappato direttamente su target.user.userid quando Data.Updates.0.MemberId non è presente. |
Data.MemberDisplayName |
target.user.user_display_name |
Mappato direttamente a target.user.user_display_name . |
Data.NamespaceId |
target.resource.product_object_id |
Mappato a target.resource.product_object_id se PipelineId , AuthorizationId e AgentId non sono presenti. |
Data.NamespaceName |
target.resource.name |
Mappato a target.resource.name se PipelineName non è presente. |
Data.ownerDetails |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "OwnerDetails". |
Data.OwnerId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "OwnerId". |
Data.PipelineId |
target.resource.product_object_id |
Mappato direttamente a target.resource.product_object_id . |
Data.PipelineName |
target.resource.name |
Mappato direttamente a target.resource.name . |
Data.PipelineRevision |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "PipelineRevision". |
Data.PipelineScope |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "PipelineScope". |
Data.PlanType |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "PlanType". |
Data.PreviousAccessLevel |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "PreviousAccessLevel". |
Data.PublisherName |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "PublisherName". |
Data.Reason |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Motivo". |
Data.ReleaseId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ReleaseId". |
Data.ReleaseName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ReleaseName". |
Data.RequesterId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "RequesterId". |
Data.RetentionLeaseId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "RetentionLeaseId". |
Data.RetentionOwnerId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "RetentionOwnerId". |
Data.RunName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "RunName". |
Data.Scopes |
target.resource.attribute.labels |
Aggiunti come etichette con la chiave "Ambito". |
Data.StageName |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "StageName". |
Data.StartTime |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "StartTime". |
Data.TargetUser |
target.user.userid |
Mappato direttamente a target.user.userid . |
Data.Timestamp |
metadata.event_timestamp |
Analizzato e mappato a metadata.event_timestamp . |
Data.TokenType |
target.resource.attribute.labels |
Aggiunto come etichetta con la chiave "TokenType". |
Data.Updates.0.GroupId |
target.group.product_object_id |
Mappato direttamente a target.group.product_object_id . |
Data.Updates.0.MemberId |
target.user.userid |
Mappato direttamente a target.user.userid . |
Data.ValidFrom |
target.resource.attribute.labels |
Aggiunta come etichetta con la chiave "ValidFrom". |
Data.ValidTo |
target.resource.attribute.labels |
Aggiunta come etichetta con la chiave "ValidTo". |
DewPoint |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "DewPoint". |
Details |
metadata.description |
Mappato direttamente a metadata.description . |
Humidity |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Umidità". |
Icon |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Icona". |
Id |
metadata.product_log_id |
Mappato direttamente a metadata.product_log_id . |
IpAddress |
principal.ip |
Mappato direttamente a principal.ip . |
MoonPhase |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "MoonPhase". |
Moonrise |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Alba della luna". |
Moonset |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Tramonto della luna". |
OperationName |
metadata.product_event_type |
Mappato direttamente a metadata.product_event_type . |
Precipitation |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Precipitazioni". |
Pressure |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Pressione". |
ProjectId |
target.resource_ancestors.product_object_id |
Utilizzato per compilare il campo product_object_id all'interno di target.resource_ancestors quando l'elemento principale è di tipo CLOUD_PROJECT . |
ProjectName |
target.resource_ancestors.name , target.resource.attribute.labels |
Utilizzato per compilare il campo name all'interno di target.resource_ancestors quando l'elemento principale è di tipo CLOUD_PROJECT . Aggiunto anche come etichetta a target.resource.attribute.labels con la chiave "ProjectName". |
RoleLocation |
target.location.name |
Mappato direttamente a target.location.name . |
ScopeDisplayName |
target.resource_ancestors.name |
Utilizzato per compilare il campo name all'interno di target.resource_ancestors quando l'elemento principale è di tipo CLOUD_ORGANIZATION . |
ScopeId |
target.resource_ancestors.product_object_id |
Utilizzato per compilare il campo product_object_id all'interno di target.resource_ancestors quando l'elemento principale è di tipo CLOUD_ORGANIZATION . |
ScopeType |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "ScopeType". |
Sunrise |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Sunrise". |
Sunset |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Tramonto". |
Temperature |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Temperatura". |
TenantId |
metadata.product_deployment_id , additional.fields |
Mappato direttamente a metadata.product_deployment_id . Aggiunto anche come campo aggiuntivo con la chiave "TenantId". |
TimeGenerated |
metadata.event_timestamp |
Analizzato e mappato a metadata.event_timestamp . |
UserAgent |
network.http.user_agent , network.http.parsed_user_agent |
Mappato direttamente a network.http.user_agent . Inoltre, è stato analizzato e mappato a network.http.parsed_user_agent . |
UVIndex |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "UVIndex". |
Visibility |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "Visibilità". |
WindDirection |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "WindDirection". |
WindSpeed |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "WindSpeed". |
_Internal_WorkspaceResourceId |
additional.fields |
Aggiunto come campo aggiuntivo con la chiave "workspace_resource_id". |
N/A | metadata.event_type |
Determinato dalla logica in base a OperationName e ad altri campi. Se non viene trovata una corrispondenza con un tipo di evento specifico, il valore predefinito è "GENERIC_EVENT". I valori possibili includono "STATUS_SHUTDOWN", "RESOURCE_CREATION", "STATUS_UPDATE", "USER_RESOURCE_DELETION", "RESOURCE_READ", "RESOURCE_WRITTEN", "RESOURCE_DELETION" e "GROUP_MODIFICATION". |
N/A | metadata.vendor_name |
Imposta su "Microsoft". |
N/A | metadata.product_name |
Imposta "Azure DevOps". |
N/A | metadata.log_type |
Imposta il valore su "AZURE_DEVOPS". |
N/A | principal.user.account_type |
Imposta "SERVICE_ACCOUNT_TYPE" se AuthenticationMechanism contiene "ServicePrincipal", altrimenti imposta "CLOUD_ACCOUNT_TYPE". |
N/A | target.asset.attribute.cloud.environment |
Imposta su MICROSOFT_AZURE . |
N/A | security_result.action |
Imposta "ALLOW" per le operazioni riuscite (Riuscita, Creata, Modificata, Eseguita, Aggiornata, Rimossa) e "BLOCK" per le operazioni non riuscite (Non riuscita, Timeout). |
N/A | extensions.auth.mechanism |
Imposta su "USERNAME_PASSWORD" se summary è "UserAuthToken". |
N/A | target.resource.resource_type |
Impostato su "SETTING" se è presente pipeline_id , "CREDENTIAL" se è presente authorization_id , "DEVICE" se è presente agent_id o "DATABASE" se è presente namespace_id . In caso contrario, in alcuni casi viene impostato su "STORAGE_BUCKET" in base a operationName . |
N/A | target.resource.resource_subtype |
Impostato su "Pipeline" se è presente pipeline_id , "Token" se è presente authorization_id , "Agente" se è presente agent_id o "Spazio dei nomi" se è presente namespace_id . |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.