Raccogliere i log di controllo di Workday

Supportato in:

Questo documento spiega come importare i log di controllo di Workday in Google Security Operations utilizzando AWS S3. Il parser identifica innanzitutto il tipo di evento specifico dai log in base all'analisi dei pattern dei dati CSV. Poi, estrae e struttura i campi pertinenti in base al tipo identificato, mappandoli a un modello UDM (Unified Data Model) per un'analisi di sicurezza coerente.

Prima di iniziare

Assicurati di soddisfare i seguenti prerequisiti:

  • Istanza Google SecOps
  • Accesso privilegiato ad AWS
  • Accesso con privilegi a Workday

Configura il bucket AWS S3 e IAM per Google SecOps

  1. Crea un bucket Amazon S3 seguendo questa guida utente: Creazione di un bucket.
  2. Salva il nome e la regione del bucket per riferimento futuro (ad esempio, workday-audit-logs).
  3. Crea un utente seguendo questa guida utente: Creazione di un utente IAM.
  4. Seleziona l'utente creato.
  5. Seleziona la scheda Credenziali di sicurezza.
  6. Fai clic su Crea chiave di accesso nella sezione Chiavi di accesso.
  7. Seleziona Servizio di terze parti come Caso d'uso.
  8. Fai clic su Avanti.
  9. (Facoltativo) Aggiungi il tag della descrizione.
  10. Fai clic su Crea chiave di accesso.
  11. Fai clic su Scarica file CSV per salvare la chiave di accesso e la chiave di accesso segreta per riferimento futuro.
  12. Fai clic su Fine.
  13. Seleziona la scheda Autorizzazioni.
  14. Fai clic su Aggiungi autorizzazioni nella sezione Criteri per le autorizzazioni.
  15. Seleziona Aggiungi autorizzazioni.
  16. Seleziona Allega direttamente i criteri.
  17. Cerca e seleziona il criterio AmazonS3FullAccess.
  18. Fai clic su Avanti.
  19. Fai clic su Aggiungi autorizzazioni.

Crea l'utente di sistema di integrazione (ISU) di Workday

  1. In Workday, cerca Create Integration System User > Ok.
  2. Compila il campo Nome utente (ad esempio, audit_s3_user).
  3. Fai clic su OK.
  4. Reimposta la password andando su Azioni correlate > Sicurezza > Reimposta password.
  5. Seleziona Mantieni regole password per impedire la scadenza della password.
  6. Cerca Create Security Group > Integration System Security Group (Unconstrained).
  7. Fornisci un nome (ad esempio ISU_Audit_S3) e aggiungi l'utente di sistema integrato a Integration System Users (Utenti di sistema integrato).
  8. Cerca Domain Security Policies for Functional Area > System.
  9. Per Audit Trail, seleziona Azioni > Modifica autorizzazioni.
  10. In Ottieni solo, aggiungi il gruppo ISU_Audit_S3.
  11. Fai clic su Ok > Attiva modifiche in attesa del criterio di sicurezza.

Configurare il report personalizzato di Workday

  1. In Workday, cerca Crea report personalizzato.
  2. Fornisci i seguenti dettagli di configurazione:
    • Nome: inserisci un nome univoco (ad esempio, Audit_Trail_BP_JSON).
    • Tipo: seleziona Avanzate.
    • Origine dati: seleziona Audit trail - Business Process.
    • Fai clic su OK.
    • (Facoltativo) Aggiungi filtri per Tipo di processo aziendale o Data di validitร .
  3. Vai alla scheda Output.
  4. Seleziona Attiva come servizio web, Ottimizzato per le prestazioni e Formato JSON.
  5. Fai clic su Ok > Fine.
  6. Apri il report e fai clic su Condividi > aggiungi ISU_Audit_S3 con autorizzazione di visualizzazione > Ok.
  7. Vai ad Azioni correlate > Servizio web > Visualizza URL.
  8. Copia l'URL JSON (ad esempio, https://wd-services1.workday.com/ccx/service/customreport2/<tenant>/<user>/Audit_Trail_BP_JSON?format=json).

Configura il ruolo e il criterio IAM per i caricamenti S3

  1. JSON delle policy (sostituisci workday-audit-logs se hai inserito un nome del bucket diverso):

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowPutWorkdayObjects",
          "Effect": "Allow",
          "Action": "s3:PutObject",
          "Resource": "arn:aws:s3:::workday-audit-logs/*"
        }
      ]
    }
    
  2. Vai alla console AWS > IAM > Policy > Crea policy > scheda JSON.

  3. Copia e incolla le norme.

  4. Fai clic su Avanti > Crea policy.

  5. Vai a IAM > Ruoli > Crea ruolo > Servizio AWS > Lambda.

  6. Allega il criterio appena creato.

  7. Assegna al ruolo il nome WriteWorkdayToS3Role e fai clic su Crea ruolo.

Crea la funzione Lambda

Impostazione Valore
Nome workday_audit_to_s3
Tempo di esecuzione Python 3.13
Architettura x86_64
Ruolo di esecuzione WriteWorkdayToS3Role
  1. Dopo aver creato la funzione, apri la scheda Codice, elimina lo stub e incolla il codice riportato di seguito (workday_audit_to_s3.py).

    #!/usr/bin/env python3
    
    import os, json, gzip, io, uuid, base64, datetime as dt, urllib.request, urllib.error
    import boto3
    
    WD_USER   = os.environ["WD_USER"]
    WD_PASS   = os.environ["WD_PASS"]
    WD_URL    = os.environ["WD_URL"]
    S3_BUCKET = os.environ["S3_BUCKET_NAME"]
    
    def fetch_report() -> bytes:
        credentials = f"{WD_USER}:{WD_PASS}".encode()
        auth_header = b"Basic " + base64.b64encode(credentials)
        req = urllib.request.Request(WD_URL, headers={"Authorization": auth_header.decode()})
        with urllib.request.urlopen(req, timeout=30) as r:
            return r.read()  # raw JSON bytes
    
    def upload(payload: bytes, ts: dt.datetime) -> None:
        key = f"{ts:%Y/%m/%d}/workday-audit-{uuid.uuid4()}.json.gz"
        buf = io.BytesIO()
        with gzip.GzipFile(fileobj=buf, mode="w") as gz:
            gz.write(payload)
        buf.seek(0)
        boto3.client("s3").upload_fileobj(buf, S3_BUCKET, key)
    
    def lambda_handler(event=None, context=None):
        now = dt.datetime.utcnow().replace(microsecond=0)
        data = fetch_report()
        upload(data, now)
        print(f"Uploaded Workday audit report ({len(data)} bytes raw)")
    
    if __name__ == "__main__":
        lambda_handler()
    
  2. Vai a Configurazione > Variabili di ambiente > Modifica > Aggiungi nuova variabile di ambiente.

  3. Inserisci le seguenti variabili di ambiente, sostituendo il valore con il tuo.

    Variabili di ambiente

    Chiave Valori di esempio
    WD_USER audit_s3_user
    WD_PASS Wrokday-Password
    WD_URL https://.../Audit_Trail_BP_JSON?format=json
    S3_BUCKET_NAME workday-audit-logs
  4. Dopo aver creato la funzione, rimani sulla relativa pagina (o apri Lambda > Funzioni > la tua funzione).

  5. Seleziona la scheda Configurazione.

  6. Nel riquadro Configurazione generale, fai clic su Modifica.

  7. Modifica Timeout impostando 5 minuti (300 secondi) e fai clic su Salva.

Pianifica la funzione Lambda (EventBridge Scheduler)

  1. Vai a Configurazione > Trigger > Aggiungi trigger > EventBridge Scheduler > Crea regola.
  2. Fornisci i seguenti dettagli di configurazione:
    • Nome: daily-workday-audit export
    • Pattern di pianificazione: espressione cron.
    • Espressione: 20 2 * * ? * (viene eseguita ogni giorno alle 02:20 UTC).
  3. Lascia invariate le altre impostazioni predefinite e fai clic su Crea.

Configura un feed in Google SecOps per importare gli audit log di Workday

  1. Vai a Impostazioni SIEM > Feed.
  2. Fai clic su + Aggiungi nuovo feed.
  3. Nel campo Nome feed, inserisci un nome per il feed (ad esempio, Workday Audit Logs).
  4. Seleziona Amazon S3 V2 come Tipo di origine.
  5. Seleziona Audit di Workday come Tipo di log.
  6. Fai clic su Ottieni un service account.
  7. Fai clic su Avanti.
  8. Specifica i valori per i seguenti parametri di input:
    • URI S3: l'URI del bucket
      • s3://workday-audit-logs/.
        • Sostituisci workday-audit-logs con il nome effettivo del bucket.
    • Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
    • Etร  massima del file: includi i file modificati nell'ultimo numero di giorni. Il valore predefinito รจ 180 giorni.
    • ID chiave di accesso: chiave di accesso utente con accesso al bucket S3.
    • Chiave di accesso segreta: chiave segreta dell'utente con accesso al bucket S3.
    • Spazio dei nomi dell'asset: lo spazio dei nomi dell'asset.
    • Etichette di importazione: l'etichetta da applicare agli eventi di questo feed.
  9. Fai clic su Avanti.
  10. Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.

Tabella di mappatura UDM

Campo log Mappatura UDM Logic
Account metadata.event_type Se il campo "Account" non รจ vuoto, il campo "metadata.event_type" รจ impostato su "USER_RESOURCE_UPDATE_CONTENT".
Account principal.user.primaryId L'ID utente viene estratto dal campo "Account" utilizzando un pattern grok e mappato a principal.user.primaryId.
Account principal.user.primaryName Il nome visualizzato dell'utente viene estratto dal campo "Account" utilizzando un pattern grok e mappato a "principal.user.primaryName".
ActivityCategory metadata.event_type Se il campo "ActivityCategory" รจ "READ", il campo "metadata.event_type" รจ impostato su "RESOURCE_READ". Se "WRITE", รจ impostato su "RESOURCE_WRITTEN".
ActivityCategory metadata.product_event_type Mappato direttamente dal campo "ActivityCategory".
AffectedGroups target.user.group_identifiers Mappato direttamente dal campo "AffectedGroups".
Area target.resource.attribute.labels.area.value Mappato direttamente dal campo "Area".
AuthType extensions.auth.auth_details Mappato direttamente dal campo "AuthType".
AuthType extensions.auth.type Mappato dal campo "AuthType" a diversi tipi di autenticazione definiti in UDM in base a valori specifici.
CFIPdeConexion src.domain.name Se il campo "CFIPdeConexion" non รจ un indirizzo IP valido, viene mappato a "src.domain.name".
CFIPdeConexion target.ip Se il campo "CFIPdeConexion" รจ un indirizzo IP valido, viene mappato a "target.ip".
ChangedRelationship metadata.description Mappato direttamente dal campo "ChangedRelationship".
ClassOfInstance target.resource.attribute.labels.class_instance.value Mappato direttamente dal campo "ClassOfInstance".
column18 about.labels.utub.value Mappato direttamente dal campo "column18".
CreatedBy principal.user.userid L'ID utente viene estratto dal campo "CreatedBy" utilizzando un pattern grok e mappato a "principal.user.userid".
CreatedBy principal.user.user_display_name Il nome visualizzato dell'utente viene estratto dal campo "CreatedBy" utilizzando un pattern grok e mappato a "principal.user.user_display_name".
Domain about.domain.name Mappato direttamente dal campo "Dominio".
EffectiveDate @timestamp Analizzato in "@timestamp" dopo la conversione nel formato "aaaa-MM-gg HH:mm:ss.SSSZ".
EntryMoment @timestamp Analizzato in "@timestamp" dopo la conversione nel formato "ISO8601".
EventType security_result.description Mappato direttamente dal campo "EventType".
Form target.resource.name Mappato direttamente dal campo "Modulo".
InstancesAdded about.resource.attribute.labels.instances_added.value Mappato direttamente dal campo "InstancesAdded".
InstancesAdded target.user.attribute.roles.instances_added.name Mappato direttamente dal campo "InstancesAdded".
InstancesRemoved about.resource.attribute.labels.instances_removed.value Mappato direttamente dal campo "InstancesRemoved".
InstancesRemoved target.user.attribute.roles.instances_removed.name Mappato direttamente dal campo "InstancesRemoved".
IntegrationEvent target.resource.attribute.labels.integration_event.value Mappato direttamente dal campo "IntegrationEvent".
IntegrationStatus security_result.action_details Mappato direttamente dal campo "IntegrationStatus".
IntegrationSystem target.resource.name Mappato direttamente dal campo "IntegrationSystem".
IP src.domain.name Se il campo "IP" non รจ un indirizzo IP valido, viene mappato a "src.domain.name".
IP src.ip Se il campo "IP" รจ un indirizzo IP valido, viene mappato a "src.ip".
IsDeviceManaged additional.fields.additional1.value.string_value Se il campo "IsDeviceManaged" รจ "N", il valore รจ impostato su "Riuscito". In caso contrario, รจ impostato su "Accesso non riuscito".
IsDeviceManaged additional.fields.additional2.value.string_value Se il campo "IsDeviceManaged" รจ "N", il valore รจ impostato su "Riuscito". In caso contrario, รจ impostato su "Credenziali non valide".
IsDeviceManaged additional.fields.additional3.value.string_value Se il campo "IsDeviceManaged" รจ "N", il valore รจ impostato su "Riuscito". In caso contrario, รจ impostato su "Account bloccato".
IsDeviceManaged security_result.action_details Mappato direttamente dal campo "IsDeviceManaged".
OutputFiles about.file.full_path Mappato direttamente dal campo "OutputFiles".
Person principal.user.primaryId Se il campo "Person" inizia con "INT", l'ID utente viene estratto utilizzando un pattern grok e mappato a "principal.user.primaryId".
Person principal.user.primaryName Se il campo "Person" inizia con "INT", il nome visualizzato dell'utente viene estratto utilizzando un pattern grok e mappato a "principal.user.primaryName".
Person principal.user.user_display_name Se il campo "Persona" non inizia con "INT", viene mappato direttamente a "principal.user.user_display_name".
Person metadata.event_type Se il campo "Person" non รจ vuoto, il campo "metadata.event_type" รจ impostato su "USER_RESOURCE_UPDATE_CONTENT".
ProcessedTransaction target.resource.attribute.creation_time Analizzato in "target.resource.attribute.creation_time" dopo la conversione nel formato "gg/MM/aaaa HH:mm:ss,SSS (ZZZ)", "gg/MM/aaaa, HH:mm:ss,SSS (ZZZ)" o "MM/gg/aaaa, HH:mm:ss.SSS A ZZZ".
ProgramBy principal.user.userid Mappato direttamente dal campo "ProgramBy".
RecurrenceEndDate principal.resource.attribute.last_update_time Analizzato in "principal.resource.attribute.last_update_time" dopo la conversione nel formato "aaaa-MM-gg".
RecurrenceStartDate principal.resource.attribute.creation_time Analizzato come "principal.resource.attribute.creation_time" dopo la conversione nel formato "aaaa-MM-gg".
RequestName metadata.description Mappato direttamente dal campo "RequestName".
ResponseMessage security_result.summary Mappato direttamente dal campo "ResponseMessage".
RestrictedToEnvironment security_result.about.hostname Mappato direttamente dal campo "RestrictedToEnvironment".
RevokedSecurity security_result.outcomes.outcomes.value Mappato direttamente dal campo "RevokedSecurity".
RunFrequency principal.resource.attribute.labels.run_frequency.value Mappato direttamente dal campo "RunFrequency".
ScheduledProcess principal.resource.name Mappato direttamente dal campo "ScheduledProcess".
SecuredTaskExecuted target.resource.name Mappato direttamente dal campo "SecuredTaskExecuted".
SecureTaskExecuted metadata.event_type Se il campo "SecureTaskExecuted" contiene "Create", il campo "metadata.event_type" รจ impostato su "USER_RESOURCE_CREATION".
SecureTaskExecuted target.resource.name Mappato direttamente dal campo "SecureTaskExecuted".
SentTime @timestamp Analizzato in "@timestamp" dopo la conversione nel formato "ISO8601".
SessionId network.session_id Mappato direttamente dal campo "SessionId".
ShareBy target.user.userid Mappato direttamente dal campo "ShareBy".
SignOffTime additional.fields.additional4.value.string_value Il valore del campo "AuthFailMessage" viene inserito nell'array "additional.fields" con la chiave "Enterprise Interface Builder".
SignOffTime metadata.description Mappato direttamente dal campo "AuthFailMessage".
SignOffTime metadata.event_type Se il campo "SignOffTime" รจ vuoto, il campo "metadata.event_type" รจ impostato su "USER_LOGIN". In caso contrario, รจ impostato su "USER_LOGOUT".
SignOffTime principal.user.attribute.last_update_time Analizzato come "principal.user.attribute.last_update_time" dopo la conversione nel formato "ISO8601".
SignOnIp src.domain.name Se il campo "SignOnIp" non รจ un indirizzo IP valido, viene mappato a "src.domain.name".
SignOnIp src.ip Se il campo "SignOnIp" รจ un indirizzo IP valido, viene mappato a "src.ip".
Status metadata.product_event_type Mappato direttamente dal campo "Stato".
SystemAccount principal.user.email_addresses L'indirizzo email viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato su "principal.user.email_addresses".
SystemAccount principal.user.primaryId L'ID utente viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato a "principal.user.primaryId".
SystemAccount principal.user.primaryName Il nome visualizzato dell'utente viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato a "principal.user.primaryName".
SystemAccount src.user.userid L'ID utente secondario viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato a "src.user.userid".
SystemAccount src.user.user_display_name Il nome visualizzato dell'utente secondario viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato a "src.user.user_display_name".
SystemAccount target.user.userid L'ID utente di destinazione viene estratto dal campo "SystemAccount" utilizzando un pattern grok e mappato a "target.user.userid".
Target target.user.user_display_name Mappato direttamente dal campo "Target".
Template about.resource.name Mappato direttamente dal campo "Modello".
Tenant target.asset.hostname Mappato direttamente dal campo "Tenant".
TlsVersion network.tls.version Mappato direttamente dal campo "TlsVersion".
Transaction security_result.action_details Mappato direttamente dal campo "Transazione".
TransactionType security_result.summary Mappato direttamente dal campo "TransactionType".
TypeForm target.resource.resource_subtype Mappato direttamente dal campo "TypeForm".
UserAgent network.http.parsed_user_agent Analizzato dal campo "UserAgent" utilizzando il filtro "useragent".
UserAgent network.http.user_agent Mappato direttamente dal campo "UserAgent".
WorkdayAccount target.user.user_display_name Il nome visualizzato dell'utente viene estratto dal campo "WorkdayAccount" utilizzando un pattern grok e mappato a "target.user.user_display_name".
WorkdayAccount target.user.userid L'ID utente viene estratto dal campo "WorkdayAccount" utilizzando un pattern grok e mappato a "target.user.userid".
additional.fields.additional1.key Imposta "FailedSignOn".
additional.fields.additional2.key Imposta il valore su "InvalidCredentials".
additional.fields.additional3.key Impostato su "AccountLocked".
additional.fields.additional4.key Imposta su "Enterprise Interface Builder".
metadata.event_type Imposta inizialmente il valore "GENERIC_EVENT", che verrร  poi aggiornato in base alla logica che coinvolge altri campi.
metadata.event_type Imposta "USER_CHANGE_PERMISSIONS" per tipi di eventi specifici.
metadata.event_type Imposta "RESOURCE_WRITTEN" per tipi di eventi specifici.
metadata.log_type Codificato come "WORKDAY_AUDIT".
metadata.product_name Codificato in modo permanente su "Enterprise Interface Builder".
metadata.vendor_name Codificato in modo permanente su "Giorno lavorativo".
principal.asset.category Imposta "Telefono" se il campo "DeviceType" รจ "Telefono".
principal.resource.resource_type Codificato in modo permanente su "TASK" se il campo "ScheduledProcess" non รจ vuoto.
security_result.action Imposta "ALLOW" o "FAIL" in base ai valori dei campi "FailedSignOn", "IsDeviceManaged", "InvalidCredentials" e "AccountLocked".
security_result.summary Imposta "Riuscito" o messaggi di errore specifici in base ai valori dei campi "FailedSignOn", "IsDeviceManaged", "InvalidCredentials" e "AccountLocked".
target.resource.resource_type Codificato come "TASK" per tipi di eventi specifici.
target.resource.resource_type Codificato in modo permanente su "DATASET" se il campo "TypeForm" non รจ vuoto.
message principal.user.email_addresses Estrae l'indirizzo email dal campo "message" utilizzando un pattern grok e lo unisce a "principal.user.email_addresses" se viene trovato un pattern specifico.
message src.user.userid Cancella il campo se il campo "event.idm.read_only_udm.principal.user.userid" corrisponde a "user_target" estratto dal campo "message".
message src.user.user_display_name Cancella il campo se il campo "event.idm.read_only_udm.principal.user.userid" corrisponde a "user_target" estratto dal campo "message".
message target.user.userid Estrae l'ID utente dal campo "message" utilizzando un pattern grok e lo mappa a "target.user.userid" se viene trovato un pattern specifico.

Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.