Mengumpulkan log WP Engine

Didukung di:

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

WP Engine adalah platform hosting WordPress terkelola yang menyediakan hosting tingkat perusahaan dengan keamanan bawaan, pengoptimalan performa, dan layanan CDN. Plugin ini menghasilkan log akses, log error, dan log peristiwa CDN yang dapat dikumpulkan melalui WP Engine API.

Sebelum memulai

Pastikan Anda memiliki prasyarat berikut:

  • Instance Google SecOps
  • Project GCP dengan Cloud Storage API diaktifkan
  • Izin untuk membuat dan mengelola bucket GCS
  • Izin untuk mengelola kebijakan IAM di bucket GCS
  • Izin untuk membuat layanan Cloud Run, topik Pub/Sub, dan tugas Cloud Scheduler
  • Akses istimewa ke Portal Pengguna WP Engine dengan izin akses API
  • Akun WP Engine dengan akses API diaktifkan

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, wpengine-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.

Kumpulkan kredensial WP Engine API

Membuat kredensial API

  1. Login ke Portal Pengguna WP Engine.
  2. Klik nama profil Anda, lalu buka Profile > API Access.
  3. Klik Buat Kredensial.
  4. Salin dan simpan detail berikut di tempat yang aman:

    • Nama Pengguna API: Nama pengguna API yang dibuat
    • Sandi API: Sandi API yang dibuat (hanya ditampilkan satu kali)

Mendapatkan nama penginstalan

  1. Login ke Portal Pengguna WP Engine.
  2. Buka Situs di menu navigasi.
  3. Klik situs yang ingin Anda kumpulkan lognya.
  4. Catat Nama penginstalan yang ditampilkan di halaman ringkasan situs. Setiap lingkungan (Produksi, Staging, Pengembangan) memiliki nama penginstalan terpisah.

Menguji akses API

  • Uji kredensial Anda sebelum melanjutkan integrasi:

    # Replace with your actual credentials
    WPE_USER="your-api-username"
    WPE_PASSWORD="your-api-password"
    
    # Test API access - list installs
    curl -v -u "${WPE_USER}:${WPE_PASSWORD}" "https://api.wpengineapi.com/v1/installs"
    

Buat akun layanan untuk Cloud Run Function

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

Membuat akun layanan

  1. Di GCP Console, buka IAM & Admin > Service Accounts.
  2. Klik Create Service Account.
  3. Berikan detail konfigurasi berikut:
    • Nama akun layanan: Masukkan wpengine-logs-collector-sa
    • Deskripsi akun layanan: Masukkan Service account for Cloud Run function to collect WP Engine logs
  4. Klik Create and Continue.
  5. Di bagian Berikan akun layanan ini akses ke 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 GCS dan mengelola file status
  • Cloud Run Invoker: Mengizinkan Pub/Sub memanggil fungsi
  • Cloud Functions Invoker: Mengizinkan pemanggilan fungsi

Memberikan izin IAM pada bucket GCS

Beri akun layanan izin tulis di bucket GCS:

  1. Buka Cloud Storage > Buckets.
  2. Klik nama bucket Anda (misalnya, wpengine-logs).
  3. Buka tab Izin.
  4. Klik Grant access.
  5. Berikan detail konfigurasi berikut:
    • Tambahkan prinsipal: Masukkan email akun layanan (misalnya, wpengine-logs-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 Konsol GCP, buka Pub/Sub > Topics.
  2. Klik Create topic.
  3. Berikan detail konfigurasi berikut:
    • ID Topik: Masukkan wpengine-logs-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 WP Engine API dan menuliskannya ke GCS.

  1. Di GCP 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 wpengine-logs-collector
    Region Pilih region yang cocok dengan bucket GCS 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 topik wpengine-logs-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 akun layanan wpengine-logs-collector-sa.
  9. Buka tab Containers:

    1. Klik Variables & Secrets.
    2. Klik + Tambahkan variabel untuk setiap variabel lingkungan:
    Nama Variabel Nilai Contoh Deskripsi
    GCS_BUCKET wpengine-logs Nama bucket GCS
    GCS_PREFIX wpengine Awalan untuk file log
    STATE_KEY wpengine/state.json Jalur file status
    WPE_API_USER your-api-username Nama pengguna WP Engine API
    WPE_API_PASSWORD your-api-password Sandi WP Engine API
    WPE_INSTALL_ID myinstall Nama penginstalan WP Engine
    MAX_RECORDS 5000 Jumlah maksimum data per proses
    PAGE_SIZE 100 Catatan per halaman
    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 Materi:
      • Memori: Pilih 512 MiB atau yang lebih tinggi
      • CPU: Pilih 1
  12. Di bagian Penskalaan revisi:

    • Jumlah minimum instance: Masukkan 0
    • Maximum number of instances: Masukkan 100 (atau sesuaikan berdasarkan perkiraan beban)
  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:

    • File pertama: main.py:
    import functions_framework
    from google.cloud import storage
    import json
    import os
    import urllib3
    from datetime import datetime, timezone, timedelta
    import time
    import base64
    
    # Initialize HTTP client with timeouts
    http = urllib3.PoolManager(
      timeout=urllib3.Timeout(connect=5.0, read=30.0),
      retries=False,
    )
    
    # Initialize Storage client
    storage_client = storage.Client()
    
    # Environment variables
    GCS_BUCKET = os.environ.get('GCS_BUCKET')
    GCS_PREFIX = os.environ.get('GCS_PREFIX', 'wpengine')
    STATE_KEY = os.environ.get('STATE_KEY', 'wpengine/state.json')
    WPE_API_USER = os.environ.get('WPE_API_USER')
    WPE_API_PASSWORD = os.environ.get('WPE_API_PASSWORD')
    WPE_INSTALL_ID = os.environ.get('WPE_INSTALL_ID')
    MAX_RECORDS = int(os.environ.get('MAX_RECORDS', '5000'))
    PAGE_SIZE = int(os.environ.get('PAGE_SIZE', '100'))
    LOOKBACK_HOURS = int(os.environ.get('LOOKBACK_HOURS', '24'))
    
    # WP Engine API base URL
    API_BASE = 'https://api.wpengineapi.com/v1'
    
    # Log types to fetch
    LOG_TYPES = ['access', 'error']
    
    def get_auth_header():
      """Generate HTTP Basic auth header for WP Engine API."""
      credentials = f"{WPE_API_USER}:{WPE_API_PASSWORD}"
      encoded = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
      return f"Basic {encoded}"
    
    @functions_framework.cloud_event
    def main(cloud_event):
      """
      Cloud Run function triggered by Pub/Sub to fetch WP Engine
      logs and write to GCS.
    
      Args:
        cloud_event: CloudEvent object containing Pub/Sub message
      """
    
      if not all([GCS_BUCKET, WPE_API_USER, WPE_API_PASSWORD, WPE_INSTALL_ID]):
        print('Error: Missing required environment variables')
        return
    
      try:
        bucket = storage_client.bucket(GCS_BUCKET)
    
        # Load state
        state = load_state(bucket, STATE_KEY)
    
        # Determine time window
        now = datetime.now(timezone.utc)
        last_offsets = {}
    
        if isinstance(state, dict) and state.get("last_offsets"):
          last_offsets = state["last_offsets"]
    
        print(f"Fetching logs for install: {WPE_INSTALL_ID}")
    
        auth_header = get_auth_header()
        all_records = []
    
        # Fetch both access and error log types
        for log_type in LOG_TYPES:
          last_offset = last_offsets.get(log_type, 0)
    
          records = fetch_logs(
            auth_header=auth_header,
            install_id=WPE_INSTALL_ID,
            log_type=log_type,
            start_offset=last_offset,
            page_size=PAGE_SIZE,
            max_records=MAX_RECORDS,
          )
    
          # Tag records with log type
          for record in records:
            record['_wpe_log_type'] = log_type
    
          all_records.extend(records)
    
          # Update offset for this log type
          if records:
            last_offsets[log_type] = last_offset + len(records)
    
          print(f"Fetched {len(records)} {log_type} log records")
    
        if not all_records:
          print("No new log records found.")
          save_state(bucket, STATE_KEY, last_offsets)
          return
    
        # Write to GCS as NDJSON
        timestamp = now.strftime('%Y%m%d_%H%M%S')
        object_key = f"{GCS_PREFIX}/logs_{timestamp}.ndjson"
        blob = bucket.blob(object_key)
    
        ndjson = '\n'.join([json.dumps(record, ensure_ascii=False) for record in all_records]) + '\n'
        blob.upload_from_string(ndjson, content_type='application/x-ndjson')
    
        print(f"Wrote {len(all_records)} records to gs://{GCS_BUCKET}/{object_key}")
    
        # Update state
        save_state(bucket, STATE_KEY, last_offsets)
    
        print(f"Successfully processed {len(all_records)} records")
    
      except Exception as e:
        print(f'Error processing logs: {str(e)}')
        raise
    
    def load_state(bucket, key):
      """Load state from GCS."""
      try:
        blob = bucket.blob(key)
        if blob.exists():
          state_data = blob.download_as_text()
          return json.loads(state_data)
      except Exception as e:
        print(f"Warning: Could not load state: {e}")
    
      return {}
    
    def save_state(bucket, key, last_offsets: dict):
      """Save the last offsets to GCS state file."""
      try:
        state = {'last_offsets': last_offsets}
        blob = bucket.blob(key)
        blob.upload_from_string(
          json.dumps(state, indent=2),
          content_type='application/json'
        )
        print(f"Saved state: last_offsets={last_offsets}")
      except Exception as e:
        print(f"Warning: Could not save state: {e}")
    
    def fetch_logs(auth_header: str, install_id: str, log_type: str, start_offset: int, page_size: int, max_records: int):
      """
      Fetch logs from WP Engine API with offset-based pagination
      and rate limiting.
    
      Args:
        auth_header: HTTP Basic auth header
        install_id: WP Engine install name
        log_type: Log type to fetch (access or error)
        start_offset: Starting offset for pagination
        page_size: Number of records per page
        max_records: Maximum total records to fetch
    
      Returns:
        List of log records
      """
      headers = {
        'Authorization': auth_header,
        'Accept': 'application/json',
        'User-Agent': 'GoogleSecOps-WPEngineCollector/1.0'
      }
    
      records = []
      offset = start_offset
      page_num = 0
      backoff = 1.0
    
      while True:
        page_num += 1
    
        if len(records) >= max_records:
          print(f"Reached max_records limit ({max_records}) for {log_type}")
          break
    
        limit = min(page_size, max_records - len(records))
        url = f"{API_BASE}/installs/{install_id}/logs?type={log_type}&limit={limit}&offset={offset}"
    
        try:
          response = http.request('GET', url, headers=headers)
    
          # Handle rate limiting with exponential backoff
          if response.status == 429:
            retry_after = int(response.headers.get('Retry-After', str(int(backoff))))
            print(f"Rate limited (429). Retrying after {retry_after}s...")
            time.sleep(retry_after)
            backoff = min(backoff * 2, 30.0)
            continue
    
          backoff = 1.0
    
          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'))
    
          page_results = data.get('results', data.get('data', []))
    
          if not page_results:
            print(f"No more results (empty page) for {log_type}")
            break
    
          print(f"Page {page_num}: Retrieved {len(page_results)} {log_type} events")
          records.extend(page_results)
    
          offset += len(page_results)
    
          # If we got fewer results than requested, no more pages
          if len(page_results) < limit:
            print(f"Last page reached for {log_type}")
            break
    
        except Exception as e:
          print(f"Error fetching {log_type} logs: {e}")
          return []
    
      print(f"Retrieved {len(records)} total {log_type} records from {page_num} pages")
      return records
    
    • File kedua: 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 GCP Console, buka Cloud Scheduler.
  2. Klik Create Job.
  3. Berikan detail konfigurasi berikut:

    Setelan Nilai
    Nama wpengine-logs-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 topik wpengine-logs-trigger
    Isi pesan {} (objek JSON kosong)
  4. Klik Create.

Opsi frekuensi jadwal

Pilih frekuensi berdasarkan volume log dan persyaratan latensi:

Frekuensi Ekspresi Cron Kasus Penggunaan
Setiap 5 menit */5 * * * * Volume tinggi, latensi rendah
Setiap 15 menit */15 * * * * Volume sedang
Setiap jam 0 * * * * Standar (direkomendasikan)
Setiap 6 jam 0 */6 * * * Volume rendah, pemrosesan batch
Harian 0 0 * * * Pengumpulan data historis

Menguji integrasi

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

    Fetching logs for install: myinstall
    Page 1: Retrieved X access events
    Fetched X access log records
    Page 1: Retrieved X error events
    Fetched X error log records
    Wrote X records to gs://wpengine-logs/wpengine/logs_YYYYMMDD_HHMMSS.ndjson
    Successfully processed X records
    
  8. Buka Cloud Storage > Buckets.

  9. Klik nama bucket Anda (wpengine-logs).

  10. Buka folder wpengine/.

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

Jika Anda melihat error dalam log:

  • HTTP 401: Periksa kredensial API di variabel lingkungan
  • HTTP 403: Pastikan akses API diaktifkan di Portal Pengguna WP Engine
  • HTTP 429: Pembatasan kecepatan - fungsi akan otomatis mencoba lagi dengan penundaan
  • Variabel lingkungan tidak ada: Periksa apakah semua variabel yang diperlukan telah ditetapkan

Mengonfigurasi feed di Google SecOps untuk menyerap log WP Engine

  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, WP Engine Logs).
  5. Pilih Google Cloud Storage V2 sebagai Source type.
  6. Pilih WPEngine sebagai Jenis log.
  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.

  9. Klik Berikutnya.

  10. Tentukan nilai untuk parameter input berikut:

    • URL bucket penyimpanan: Masukkan URI bucket GCS dengan jalur awalan:

      gs://wpengine-logs/wpengine/
      
      • Ganti:
        • wpengine-logs: Nama bucket GCS Anda.
        • wpengine: Awalan/jalur folder opsional tempat log disimpan (biarkan kosong untuk root).
    • 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: Menyertakan file yang diubah 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 GCS Anda.

  1. Buka Cloud Storage > Buckets.
  2. Klik nama bucket Anda.
  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.

Tabel pemetaan UDM

Kolom Log Pemetaan UDM Logika
request, sig, blog_id, kind, name, slug, ver additional.fields Digabungkan dengan label dari permintaan (sebagai request_label), sig (sebagai sig_label), blog_id (sebagai blog_id_label), kind (sebagai kind_label), name (sebagai name_label), slug (sebagai slug_label), ver (sebagai ver_label) jika masing-masing tidak kosong
msg metadata.description Nilai disalin secara langsung
metadata.event_type Ditetapkan ke "STATUS_UPDATE" jika has_principal benar, atau "GENERIC_EVENT"
protokol network.application_protocol Nilai disalin secara langsung
versi network.application_protocol_version Dikonversi ke string
metode network.http.method Nilai disalin secara langsung
user_agent network.http.parsed_user_agent Dikonversi ke parseduseragent
secure_url network.http.referral_url Nilai disalin secara langsung
response_code network.http.response_code Dikonversi menjadi string, lalu menjadi bilangan bulat
user_agent network.http.user_agent Nilai disalin secara langsung
received_bytes network.received_bytes Dikonversi menjadi string, lalu menjadi uinteger
Hostname principal.asset.hostname Nilai disalin secara langsung
client_ip principal.asset.ip Nilai disalin secara langsung
Hostname principal.hostname Nilai disalin secara langsung
client_ip principal.ip Nilai disalin secara langsung
port principal.port Dikonversi menjadi string, lalu menjadi bilangan bulat
pid principal.process.pid Dikonversi ke string
scan_type, scan_value security_result.description Nilai dari scan_value jika tidak kosong, atau dari scan_type jika tidak kosong

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