Mengumpulkan log CloudM

Versi Parser: 6.0

Didukung di:

Dokumen ini menjelaskan cara menyerap log CloudM ke Google Security Operations menggunakan Google Cloud Storage V2.

CloudM adalah platform SaaS untuk Google Workspace dan Microsoft 365 yang menyediakan otomatisasi alur kerja untuk orientasi dan penghentian pengguna, pencadangan data, pengarsipan, dan migrasi. CloudM Automate menghasilkan log audit lengkap dari semua tindakan yang dilakukan di seluruh domain Anda, termasuk peristiwa pengelolaan pengguna, langkah-langkah alur kerja penghentian penggunaan, perubahan konfigurasi, dan operasi terkait keamanan. Data log audit dari tahun lalu dipertahankan.

Sebelum memulai

Pastikan Anda memiliki prasyarat berikut:

  • Instance Google SecOps
  • Project Google Cloud dengan Cloud Storage API diaktifkan
  • Izin untuk membuat dan mengelola bucket Cloud Storage
  • Izin untuk mengelola kebijakan Identity and Access Management (IAM) pada bucket Cloud Storage
  • Izin untuk membuat layanan Cloud Run, topik Pub/Sub, dan tugas Cloud Scheduler
  • Akses administrator ke instance CloudM Automate Anda dengan izin Edit Global Settings
  • URL instance CloudM Automate Anda (misalnya, yourcompany.cloudm.io)
  • ID domain CloudM Anda

Mengumpulkan kredensial CloudM Automate

Membuat peran khusus untuk akses log API

  1. Login ke instance CloudM Automate Anda.
  2. Buka Setelan > Peran.
  3. Klik Tambahkan Peran untuk membuat peran baru.
  4. Di kolom Role Name, masukkan nama deskriptif (misalnya, Google SecOps Log Reader).
  5. Di daftar izin, aktifkan izin berikut:

    • Melihat Log: Memberikan kemampuan untuk melihat semua log aplikasi.
  6. Simpan peran.

Buat akun layanan dan tetapkan peran

  1. Di CloudM Automate, buka Settings > Roles.
  2. Buat atau identifikasi akun layanan yang akan digunakan untuk akses API.
  3. Tetapkan peran Google SecOps Log Reader ke akun layanan.
  4. Pastikan peran ditetapkan dengan cakupan global sehingga akun layanan dapat mengakses log di seluruh domain.

Mendapatkan token akses akun layanan

  1. Buat token akses untuk akun layanan.
  2. Token akses digunakan sebagai token Bearer di header Authorization saat membuat permintaan API ke CloudM Logs API.
  3. Catat nilai berikut:

    • URL Instance Automate: URL instance CloudM Automate Anda (misalnya, yourcompany.cloudm.io)
    • ID Domain: ID domain CloudM Anda
    • Token Akses Akun Layanan: Token Bearer untuk autentikasi API

Verifikasi izin

Untuk memverifikasi bahwa akun memiliki izin yang diperlukan:

  1. Login ke CloudM Automate.
  2. Buka Setelan > Peran.
  3. Pastikan akun layanan memiliki izin Lihat Log yang ditetapkan dengan cakupan global.
  4. Jika Anda tidak dapat melihat opsi ini, hubungi administrator Anda untuk memberikan izin Edit Setelan Global dan Lihat Log.

Menguji akses API

  • Uji kredensial Anda sebelum melanjutkan integrasi:

    # Replace with your actual credentials
    CLOUDM_INSTANCE="yourcompany.cloudm.io"
    DOMAIN_ID="your-domain-id"
    ACCESS_TOKEN="your-access-token"
    
    # Test API access
    curl -v -H "Authorization: Bearer ${ACCESS_TOKEN}" \
      "https://${CLOUDM_INSTANCE}/_ah/api/events/v1/${DOMAIN_ID}?from=$(date -u +%Y-%m-%d)&to=$(date -u +%Y-%m-%d)"
    

    Respons yang berhasil akan menampilkan array JSON peristiwa log audit.

Izin API yang diperlukan

  • Akun layanan memerlukan izin berikut:

    Izin Tingkat Akses Tujuan
    Melihat Log Global Mengambil semua peristiwa log audit dari CloudM Automate

Membuat bucket Google Cloud Storage

  1. Buka Konsol Google Cloud.
  2. Pilih project Anda atau buat project baru.
  3. Di menu navigasi, buka Cloud Storage > Buckets.
  4. Klik Create bucket.
  5. Berikan detail konfigurasi berikut:

    Setelan Nilai
    Beri nama bucket Anda Masukkan nama yang unik secara global (misalnya, cloudm-audit-logs)
    Location type Pilih berdasarkan kebutuhan Anda (Region, Dual-region, Multi-region)
    Location Pilih lokasi (misalnya, us-central1)
    Kelas penyimpanan Standar (direkomendasikan untuk log yang sering diakses)
    Access control Seragam (direkomendasikan)
    Alat perlindungan Opsional: Aktifkan pembuatan versi objek atau kebijakan retensi
  6. Klik Create.

Buat akun layanan untuk Cloud Run Function

Fungsi Cloud Run memerlukan akun layanan dengan izin untuk menulis ke bucket Cloud Storage dan dipanggil oleh Pub/Sub.

Membuat akun layanan

  1. Di Google Cloud Console, buka IAM & Admin > Service Accounts.
  2. Klik Create Service Account.
  3. Berikan detail konfigurasi berikut:
    • Nama akun layanan: Masukkan cloudm-audit-collector-sa
    • Deskripsi akun layanan: Masukkan Service account for Cloud Run function to collect CloudM audit logs
  4. Klik Create and Continue.
  5. Di bagian Grant this service account access to project, tambahkan peran berikut:

    1. Klik Pilih peran.
    2. Telusuri dan pilih Storage Object Admin.
    3. Klik + Add another role.
    4. Telusuri dan pilih Cloud Run Invoker.
    5. Klik + Add another role.
    6. Telusuri dan pilih Cloud Functions Invoker.
  6. Klik Lanjutkan.

  7. Klik Done.

    Peran ini diperlukan untuk:

    • Storage Object Admin: Menulis log ke bucket Cloud Storage dan mengelola file status
    • Cloud Run Invoker: Mengizinkan Pub/Sub memanggil fungsi
    • Cloud Functions Invoker: Mengizinkan pemanggilan fungsi

Memberikan izin IAM pada bucket Cloud Storage

Beri akun layanan izin tulis di bucket Cloud Storage:

  1. Buka Cloud Storage > Buckets.
  2. Klik nama bucket Anda (cloudm-audit-logs).
  3. Buka tab Izin.
  4. Klik Grant access.
  5. Berikan detail konfigurasi berikut:

    • Tambahkan prinsipal: Masukkan email akun layanan (cloudm-audit-collector-sa@PROJECT_ID.iam.gserviceaccount.com)
    • Tetapkan peran: Pilih Storage Object Admin
  6. Klik Simpan.

Membuat topik Pub/Sub

Buat topik Pub/Sub yang akan dipublikasikan oleh Cloud Scheduler dan akan dilanggan oleh fungsi Cloud Run.

  1. Di Google Cloud Console, buka Pub/Sub > Topics.
  2. Klik Create topic.
  3. Berikan detail konfigurasi berikut:

    • ID Topik: Masukkan cloudm-audit-trigger
    • Biarkan setelan lainnya menggunakan setelan default
  4. Klik Create.

Membuat fungsi Cloud Run untuk mengumpulkan log

Fungsi Cloud Run akan dipicu oleh pesan Pub/Sub dari Cloud Scheduler untuk mengambil log dari CloudM Automate Logs API dan menuliskannya ke Cloud Storage.

  1. Di Google Cloud Console, buka Cloud Run.
  2. Klik Create service.
  3. Pilih Function (gunakan editor inline untuk membuat fungsi).
  4. Di bagian Konfigurasi, berikan detail konfigurasi berikut:

    Setelan Nilai
    Nama layanan cloudm-audit-collector
    Region Pilih region yang cocok dengan bucket Cloud Storage Anda (misalnya, us-central1)
    Runtime Pilih Python 3.12 atau yang lebih baru
  5. Di bagian Pemicu (opsional):

    1. Klik + Tambahkan pemicu.
    2. Pilih Cloud Pub/Sub.
    3. Di Select a Cloud Pub/Sub topic, pilih cloudm-audit-trigger.
    4. Klik Simpan.
  6. Di bagian Authentication:

    1. Pilih Wajibkan autentikasi.
    2. Periksa Identity and Access Management (IAM).
  7. Scroll ke bawah dan luaskan Containers, Networking, Security.

  8. Buka tab Security:

    • Akun layanan: Pilih cloudm-audit-collector-sa
  9. Buka tab Containers:

    1. Klik Variables & Secrets.
    2. Klik + Add variable untuk setiap variabel lingkungan:

      Nama Variabel Nilai Contoh Deskripsi
      GCS_BUCKET cloudm-audit-logs Nama bucket Cloud Storage
      GCS_PREFIX cloudm-audit Awalan untuk file log
      STATE_KEY cloudm-audit/state.json Jalur file status
      CLOUDM_INSTANCE_URL yourcompany.cloudm.io URL instance CloudM Automate
      CLOUDM_DOMAIN_ID your-domain-id ID domain CloudM
      CLOUDM_ACCESS_TOKEN your-access-token Token Bearer akun layanan CloudM
      LOOKBACK_HOURS 24 Periode lihat balik awal
  10. Di bagian Variables & Secrets, scroll ke bawah ke Requests:

    • Waktu tunggu permintaan: Masukkan 600 detik (10 menit)
  11. Buka tab Setelan:

    • Di bagian Resources:

      • Memori: Pilih 512 MiB atau yang lebih tinggi
      • CPU: Pilih 1
  12. Di bagian Penskalaan revisi:

    • Minimum number of instances: Masukkan 0
    • Maximum number of instances: Masukkan 100
  13. Klik Create.

  14. Tunggu hingga layanan dibuat (1-2 menit).

  15. Setelah layanan dibuat, editor kode inline akan terbuka secara otomatis.

Menambahkan kode fungsi

  1. Masukkan main di kolom Entry point.
  2. Di editor kode inline, buat dua file:

    • main.py:

      import functions_framework
      from google.cloud import storage
      import json
      import os
      import urllib3
      from datetime import datetime, timezone, timedelta
      
      http = urllib3.PoolManager(
        timeout=urllib3.Timeout(connect=10.0, read=60.0),
        retries=False,
      )
      
      storage_client = storage.Client()
      
      GCS_BUCKET = os.environ.get('GCS_BUCKET')
      GCS_PREFIX = os.environ.get('GCS_PREFIX', 'cloudm-audit')
      STATE_KEY = os.environ.get('STATE_KEY', 'cloudm-audit/state.json')
      CLOUDM_INSTANCE_URL = os.environ.get('CLOUDM_INSTANCE_URL', '').rstrip('/')
      CLOUDM_DOMAIN_ID = os.environ.get('CLOUDM_DOMAIN_ID')
      CLOUDM_ACCESS_TOKEN = os.environ.get('CLOUDM_ACCESS_TOKEN')
      LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
      
      @functions_framework.cloud_event
      def main(cloud_event):
        if not all([GCS_BUCKET, CLOUDM_INSTANCE_URL, CLOUDM_DOMAIN_ID, CLOUDM_ACCESS_TOKEN]):
          print('Error: Missing required environment variables')
          return
      
        try:
          bucket = storage_client.bucket(GCS_BUCKET)
          state = load_state(bucket)
          now = datetime.now(timezone.utc)
      
          if isinstance(state, dict) and state.get('last_event_date'):
            try:
              last_date = state['last_event_date']
              last_time = datetime.strptime(last_date, '%Y-%m-%d').replace(tzinfo=timezone.utc)
            except Exception as e:
              print(f"Warning: Could not parse last_event_date: {e}")
              last_time = now - timedelta(hours=LOOKBACK_HOURS)
          else:
            last_time = now - timedelta(hours=LOOKBACK_HOURS)
      
          from_date = last_time.strftime('%Y-%m-%d')
          to_date = now.strftime('%Y-%m-%d')
      
          print(f"Fetching logs from {from_date} to {to_date}")
      
          records = fetch_logs(from_date, to_date)
      
          if not records:
            print("No new log records found.")
            save_state(bucket, to_date)
            return
      
          timestamp = now.strftime('%Y%m%d_%H%M%S')
          object_key = f"{GCS_PREFIX}/cloudm_audit_{timestamp}.ndjson"
          blob = bucket.blob(object_key)
      
          ndjson = '\n'.join(
            [json.dumps(record, ensure_ascii=False, default=str) for record in records]
          ) + '\n'
          blob.upload_from_string(ndjson, content_type='application/x-ndjson')
      
          print(f"Wrote {len(records)} records to gs://{GCS_BUCKET}/{object_key}")
      
          save_state(bucket, to_date)
      
          print(f"Successfully processed {len(records)} records")
      
        except Exception as e:
          print(f'Error processing logs: {str(e)}')
          raise
      
      def fetch_logs(from_date, to_date):
        instance = CLOUDM_INSTANCE_URL
        if not instance.startswith('https://'):
          instance = f"https://{instance}"
      
        endpoint = f"{instance}/_ah/api/events/v1/{CLOUDM_DOMAIN_ID}"
      
        headers = {
          'Authorization': f'Bearer {CLOUDM_ACCESS_TOKEN}',
          'Accept': 'application/json',
          'User-Agent': 'GoogleSecOps-CloudMCollector/1.0'
        }
      
        url = f"{endpoint}?from={from_date}&to={to_date}"
      
        try:
          response = http.request('GET', url, headers=headers)
      
          if response.status == 429:
            retry_after = int(response.headers.get('Retry-After', '60'))
            print(f"Rate limited (429). Retry after {retry_after}s.")
            return []
      
          if response.status != 200:
            print(f"HTTP Error: {response.status}")
            response_text = response.data.decode('utf-8')
            print(f"Response body: {response_text}")
            return []
      
          data = json.loads(response.data.decode('utf-8'))
      
          if isinstance(data, list):
            records = data
          elif isinstance(data, dict):
            records = data.get('items', data.get('events', [data]))
          else:
            records = []
      
          print(f"Retrieved {len(records)} events")
          return records
      
        except Exception as e:
          print(f"Error fetching logs: {e}")
          return []
      
      def load_state(bucket):
        try:
          blob = bucket.blob(STATE_KEY)
          if blob.exists():
            return json.loads(blob.download_as_text())
        except Exception as e:
          print(f"Warning: Could not load state: {e}")
        return {}
      
      def save_state(bucket, last_event_date):
        try:
          state = {
            'last_event_date': last_event_date,
            'last_run': datetime.now(timezone.utc).isoformat()
          }
          blob = bucket.blob(STATE_KEY)
          blob.upload_from_string(
            json.dumps(state, indent=2),
            content_type='application/json'
          )
          print(f"Saved state: last_event_date={last_event_date}")
        except Exception as e:
          print(f"Warning: Could not save state: {e}")
      
    • requirements.txt:

      functions-framework==3.*
      google-cloud-storage==2.*
      urllib3>=2.0.0
      
  3. Klik Deploy untuk menyimpan dan men-deploy fungsi.

  4. Tunggu hingga deployment selesai (2-3 menit).

Buat tugas Cloud Scheduler

Cloud Scheduler akan memublikasikan pesan ke topik Pub/Sub secara berkala, sehingga memicu fungsi Cloud Run.

  1. Di Google Cloud Console, buka Cloud Scheduler.
  2. Klik Create Job.
  3. Berikan detail konfigurasi berikut:

    Setelan Nilai
    Nama cloudm-audit-collector-hourly
    Region Pilih region yang sama dengan fungsi Cloud Run
    Frekuensi 0 * * * * (setiap jam, tepat pada waktunya)
    Zona Waktu Pilih zona waktu (UTC direkomendasikan)
    Jenis target Pub/Sub
    Topik Pilih cloudm-audit-trigger
    Isi pesan {} (objek JSON kosong)
  4. Klik Create.

Menguji integrasi

  1. Di konsol Cloud Scheduler, temukan tugas Anda (cloudm-audit-collector-hourly).
  2. Klik Force run untuk memicu tugas secara manual.
  3. Tunggu beberapa detik.
  4. Buka Cloud Run > Services.
  5. Klik cloudm-audit-collector.
  6. Klik tab Logs.
  7. Pastikan fungsi berhasil dieksekusi. Cari:

    Fetching logs from YYYY-MM-DD to YYYY-MM-DD
    Retrieved X events
    Wrote X records to gs://cloudm-audit-logs/cloudm-audit/cloudm_audit_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X records
    
  8. Buka Cloud Storage > Buckets.

  9. Klik cloudm-audit-logs.

  10. Buka folder cloudm-audit/.

  11. Pastikan file .ndjson baru dibuat dengan stempel waktu saat ini.

Jika Anda melihat error dalam log:

  • HTTP 401: Pastikan variabel lingkungan CLOUDM_ACCESS_TOKEN sudah benar.
  • HTTP 403: Pastikan akun layanan memiliki izin Lihat Log dengan cakupan global.
  • HTTP 429: Pembatasan kecepatan—fungsi akan berhenti dan dilanjutkan pada jadwal berikutnya.
  • Variabel lingkungan tidak ada: Pastikan semua variabel yang diperlukan ditetapkan dalam konfigurasi fungsi Cloud Run

Mengambil akun layanan Google SecOps

Google SecOps menggunakan akun layanan unik untuk membaca data dari bucket Cloud Storage Anda. Anda harus memberi akun layanan ini akses ke bucket Anda.

Dapatkan email akun layanan

  1. Buka Setelan SIEM > Feed.
  2. Klik Tambahkan Feed Baru.
  3. Klik Konfigurasi satu feed.
  4. Di kolom Nama feed, masukkan nama untuk feed (misalnya, CloudM Audit Logs).
  5. Pilih Google Cloud Storage V2 sebagai Source type.
  6. Pilih CloudM sebagai Log type.
  7. Klik Get Service Account.

    Email akun layanan yang unik akan ditampilkan, misalnya:

    chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.com
    
  8. Salin alamat email ini untuk digunakan di langkah berikutnya.

  9. Klik Berikutnya.

  10. Tentukan nilai untuk parameter input berikut:

    • URL bucket penyimpanan: Masukkan URI bucket Cloud Storage dengan jalur awalan:

      gs://cloudm-audit-logs/cloudm-audit/
      
    • Opsi penghapusan sumber: Pilih opsi penghapusan sesuai preferensi Anda:

      • Jangan pernah: Tidak pernah menghapus file apa pun setelah transfer (direkomendasikan untuk pengujian).
      • Hapus file yang ditransfer: Menghapus file setelah transfer berhasil.
      • Hapus file yang ditransfer dan direktori kosong: Menghapus file dan direktori kosong setelah transfer berhasil.

    • Usia File Maksimum: Sertakan file yang dimodifikasi dalam beberapa hari terakhir (defaultnya adalah 180 hari).

    • Namespace aset: Namespace aset.

    • Label penyerapan: Label yang akan diterapkan ke peristiwa dari feed ini.

  11. Klik Berikutnya.

  12. Tinjau konfigurasi feed baru Anda di layar Selesaikan, lalu klik Kirim.

Memberikan izin IAM ke akun layanan Google SecOps

Akun layanan Google SecOps memerlukan peran Storage Object Viewer di bucket Cloud Storage Anda.

  1. Buka Cloud Storage > Buckets.
  2. Klik cloudm-audit-logs.
  3. Buka tab Izin.
  4. Klik Grant access.
  5. Berikan detail konfigurasi berikut:

    • Add principals: Tempel email akun layanan Google SecOps
    • Tetapkan peran: Pilih Storage Object Viewer
  6. Klik Simpan.

Parameter CloudM Logs API

CloudM Logs API mendukung parameter kueri berikut untuk memfilter peristiwa log:

Parameter Format Deskripsi
byUser Alamat email Memfilter peristiwa menurut pengguna yang melakukan tindakan (mirip dengan Pengguna di UI CloudM)
dari yyyy-MM-dd Tanggal mulai untuk filter rentang tanggal
hingga yyyy-MM-dd Tanggal akhir untuk filter rentang tanggal
contextType String Memfilter menurut jenis konteks (misalnya, profil, grup, OU)
contextName String Memfilter menurut target tindakan (misalnya, pengguna tertentu yang dihentikan aksesnya)
operasi String Filter menurut jenis operasi (misalnya, tetapkan alias, tangguhkan pengguna)
country Kode negara Memfilter menurut kode negara geolokasi

Tabel pemetaan UDM

Kolom Log Pemetaan UDM Logika
tentang tentang Nilai disalin secara langsung
Context_Name about.labels Digabungkan sebagai pasangan kunci-nilai dari about_Context_Name, about_Context_Type, labels0
Context_Type about.labels
Login_Type about.labels
Penerbit additional.fields Digabungkan dari additional_field0, additional_field1, additional_field2
SAML_code additional.fields
SAML_ACS_Url additional.fields
Operasi extensions.auth.type Disetel ke SSO jika Operasi cocok dengan SSORequest, AUTHTYPE_UNSPECIFIED jika Context_Type adalah LoginUser
Context_Type extensions.auth.type
Stempel waktu metadata.event_timestamp Mengekstrak tanggal dan waktu serta zona waktu dari Stempel Waktu, zona waktu dikonversi menjadi offset, digabungkan, dan diuraikan sebagai stempel waktu
Operasi metadata.event_type Ditetapkan ke USER_UNCATEGORIZED jika Operasi cocok dengan Update/Delete/SuspendUser/UnsuspendUser/Create, USER_LOGIN jika Operasi cocok dengan SSORequest/SSORequestFail atau Context_Type adalah LoginUser, STATUS_UPDATE jika IP tidak kosong, atau GENERIC_EVENT
Context_Type metadata.event_type
User_Agent network.http.user_agent Nilai disalin secara langsung
utama utama Diganti namanya dari principal jika Context_Type != LoginUser, atau dari target
target utama
Organization_Unit principal.administrative_domain Nilai disalin secara langsung
IP principal.ip Nilai disalin secara langsung
Kota principal.location.city Nilai disalin secara langsung
Negara principal.location.country_or_region Nilai disalin secara langsung
Geolokasi principal.location.region_latitude Mengekstrak garis lintang dari Geolokasi menggunakan grok
Geolokasi principal.location.region_longitude Mengekstrak bujur dari Geolokasi menggunakan grok
Wilayah principal.location.state Nilai disalin secara langsung
Pelaku principal.user.attribute.roles Disetel ke role.name jika Aktor bukan email dan tidak kosong, lalu digabungkan
Pelaku principal.user.email_addresses Nilai disalin langsung jika Pelaku cocok dengan regex email
Pesan principal.user.userid Mengekstrak nama pengguna dari Pesan menggunakan grok
security_result security_result Menggabungkan objek security_result
SAML_code security_result.action Ditetapkan ke ALLOW jika SAML_code cocok dengan Success, BLOCK jika RequestDenied
Pesan security_result.description Nilai disalin secara langsung
Keparahan security_result.severity Setel ke huruf besar jika Error/Kritis, INFORMATIONAL jika Info, MEDIUM jika Peringatan, atau UNKNOWN_SEVERITY
Operasi security_result.summary Nilai disalin secara langsung
target target Diganti namanya dari target jika Context_Type != LoginUser, atau dari akun utama
utama target
metadata.product_name metadata.product_name Tetapkan ke "CLOUDM"
metadata.vendor_name metadata.vendor_name Tetapkan ke "CLOUDM"

Log Perubahan

Melihat Log Perubahan untuk parser ini

Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.