Mengumpulkan log Google App Engine
Dokumen ini menjelaskan cara menyerap log Google App Engine ke Google Security Operations menggunakan Google Cloud Storage V2.
Google App Engine adalah platform serverless yang terkelola sepenuhnya untuk membangun dan men-deploy aplikasi web dan API. App Engine secara otomatis membuat log permintaan untuk permintaan HTTP dan log aplikasi dari kode Anda. Log ini dikirim ke Cloud Logging dan dapat diekspor ke Cloud Storage untuk penyerapan ke Google Security Operations.
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 sink Cloud Logging (roles/logging.configWriter)
- Aplikasi App Engine yang aktif (lingkungan standar atau fleksibel)
Membuat bucket Google Cloud Storage
- Buka Konsol Google Cloud.
- Pilih project Anda atau buat project baru.
- Di menu navigasi, buka Cloud Storage > Buckets.
- Klik Create bucket.
Berikan detail konfigurasi berikut:
Setelan Nilai Beri nama bucket Anda Masukkan nama yang unik secara global (misalnya, appengine-logs-export)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 Klik Create.
Mengonfigurasi Cloud Logging untuk mengekspor log App Engine ke GCS
Cloud Logging menggunakan sink log untuk merutekan entri log ke tujuan yang didukung, termasuk bucket Cloud Storage. Identitas penulis sink memerlukan peran Storage Object Creator (roles/storage.objectCreator) di bucket tujuan.
Membuat sink Cloud Logging
- Di Konsol Google Cloud, buka Logging > Log Router.
- Klik Create sink.
- Berikan detail konfigurasi berikut:
- Sink name: Masukkan nama deskriptif (misalnya,
appengine-to-gcs). - Deskripsi wastafel: Deskripsi opsional.
- Sink name: Masukkan nama deskriptif (misalnya,
- Klik Berikutnya.
- Di bagian Pilih layanan sink:
- Sink service: Pilih Bucket Cloud Storage.
- Pilih bucket Cloud Storage: Pilih
appengine-logs-exportdari dropdown.
- Klik Berikutnya.
Di bagian Choose logs to include in sink, masukkan kueri filter untuk memilih log App Engine. Jenis resource harus persis "gae_app".
Untuk semua log App Engine (log permintaan dan aplikasi):
resource.type="gae_app"Khusus untuk log permintaan App Engine:
resource.type="gae_app" logName="projects/PROJECT_ID/logs/appengine.googleapis.com/request_log"Untuk log aplikasi App Engine (stdout/stderr):
resource.type="gae_app" (logName="projects/PROJECT_ID/logs/stdout" OR logName="projects/PROJECT_ID/logs/stderr")Ganti
PROJECT_IDdengan project ID GCP Anda.Klik Berikutnya.
Tinjau konfigurasi, lalu klik Create sink.
Memberikan izin ke identitas penulis sink
Setelah membuat sink, Anda harus memberikan peran Storage Object Creator kepada identitas penulis sink di bucket tujuan. Identitas penulis untuk akun layanan akan terlihat seperti: serviceAccount:service-123456789012@gcp-sa-logging.iam.gserviceaccount.com
- Di halaman Log Router, temukan sink yang baru dibuat.
- Klik ikon menu (tiga titik vertikal) di samping nama sink.
- Pilih Lihat detail sinkronisasi.
- Salin Identitas penulis (email akun layanan).
- Buka Cloud Storage > Buckets.
- Klik nama bucket (
appengine-logs-export). - Buka tab Izin.
- Klik Grant access.
- Berikan detail konfigurasi berikut:
- Add principals: Tempel identitas penulis sink (email akun layanan).
- Tetapkan peran: Pilih Storage Object Creator.
- Klik Simpan.
Mengambil akun layanan Google SecOps
Google SecOps menggunakan akun layanan unik untuk membaca data dari bucket GCS Anda. Anda harus memberi akun layanan ini akses ke bucket Anda.
Mengonfigurasi feed di Google SecOps untuk menyerap log App Engine
- Buka Setelan SIEM > Feed.
- Klik Tambahkan Feed Baru.
- Klik Konfigurasi satu feed.
- Di kolom Nama feed, masukkan nama untuk feed (misalnya,
App Engine Logs). - Pilih Google Cloud Storage V2 sebagai Source type.
Pilih GCP_APP_ENGINE sebagai Log type.
Klik Get Service Account.
Email akun layanan yang unik akan ditampilkan, misalnya:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comSalin alamat email ini. Anda akan menggunakannya pada langkah berikutnya.
Klik Berikutnya.
Tentukan nilai untuk parameter input berikut:
URL bucket penyimpanan: Masukkan URI bucket GCS dengan jalur awalan:
gs://appengine-logs-export/Cloud Logging mengatur file log yang diekspor dalam hierarki direktori menurut jenis dan tanggal log. Jenis log dapat berupa nama gabungan seperti appengine.googleapis.com/request_log. File di-shard dan diberi nama dengan jangka waktu (misalnya, 08:00:00_08:59:59_S0.json).
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.
Klik Berikutnya.
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.
- Buka Cloud Storage > Buckets.
- Klik nama bucket (
appengine-logs-export). - Buka tab Izin.
- Klik Grant access.
- Berikan detail konfigurasi berikut:
- Add principals: Tempel email akun layanan Google SecOps.
- Tetapkan peran: Pilih Storage Object Viewer.
Klik Simpan.
Memahami struktur log App Engine
App Engine secara otomatis mengirimkan log permintaan dan log aplikasi ke Cloud Logging. App Engine secara otomatis memancarkan log untuk permintaan yang dikirim ke aplikasi Anda, sehingga tidak perlu menulis log permintaan. Bagian ini membahas cara menulis log aplikasi.
Log permintaan App Engine memiliki entri log yang berisi kolom protoPayload yang menyimpan objek jenis RequestLog dengan @type "type.googleapis.com/google.appengine.logging.v1.RequestLog". Jenis resource adalah "gae_app".
Secara default, payload log adalah string teks yang disimpan di kolom textPayload entri log. String ini muncul sebagai pesan di Logs Explorer dan dikaitkan dengan layanan dan versi App Engine yang menampilkannya.
Untuk menulis log terstruktur, Anda menulis log dalam bentuk satu baris JSON yang diserialisasi. Apabila Anda menyediakan log terstruktur sebagai kamus JSON, beberapa kolom khusus akan dihapus dari jsonPayload dan ditulis ke kolom yang sesuai dalam LogEntry yang dibuat. Misalnya, jika JSON Anda menyertakan properti tingkat keparahan, properti tersebut akan dihapus dari jsonPayload dan muncul sebagai tingkat keparahan entri log.
Batasan umum
Saat Anda merutekan log dari sink log ke Cloud Storage, tujuan Cloud Storage hanya berisi log permintaan. App Engine menulis log aplikasi ke folder yang berbeda.
Entri log yang dirutekan disimpan ke bucket Cloud Storage dalam batch per jam. Mungkin diperlukan waktu 2 hingga 3 jam sebelum entri pertama mulai muncul.
Di lingkungan fleksibel App Engine, logging berfungsi secara otomatis. Namun, log dikumpulkan dalam format yang berbeda. Log tidak akan dikelompokkan berdasarkan permintaan, dan log dari stdout dan stderr dikumpulkan secara terpisah.
Tabel pemetaan UDM
| Kolom log | Pemetaan UDM | Logika |
|---|---|---|
| jsonPayload.logger, taskTypeName, jsonPayload.@type, jsonPayload.backendTargetProjectNumber, jsonPayload.cacheDecision, resource.labels.version_id, resource.labels.module_id, logName, spanId, trace, protoPayload.@type, labels.clone_id, operation.producer | additional.fields | Digabungkan dengan label nilai kunci yang dibuat dari setiap kolom |
| metadata | metadata | Diganti namanya dari metadata |
| receiveTimestamp | metadata.collected_timestamp | Diuraikan menggunakan filter tanggal dengan RFC3339 |
| metadata.event_type | Ditetapkan ke "USER_LOGIN" jika has_principal, has_target, has_principal_user; "NETWORK_CONNECTION" jika has_principal dan has_target; "USER_UNCATEGORIZED" jika tidak ada has_principal dan has_target; "STATUS_UPDATE" jika ada has_principal; "USER_UNCATEGORIZED" jika ada has_principal_user; atau "GENERIC_EVENT" | |
| metadata.extensions.auth.type | Tetapkan ke "AUTHTYPE_UNSPECIFIED" jika has_principal, has_target, has_principal_user | |
| insertId | metadata.product_log_id | Nilai disalin secara langsung |
| httpRequest.requestMethod,protoPayload.method | network.http.method | Nilai dari httpRequest.requestMethod jika tidak kosong, atau protoPayload.method |
| httpRequest.userAgent | network.http.parsed_user_agent | Dikonversi ke parseduseragent |
| httpRequest.status | network.http.response_code | Dikonversi ke string, lalu ke bilangan bulat |
| httpRequest.userAgent | network.http.user_agent | Nilai disalin secara langsung |
| httpRequest.responseSize | network.received_bytes | Dikonversi ke uinteger |
| httpRequest.requestSize | network.sent_bytes | Dikonversi ke uinteger |
| utama | utama | Diganti namanya dari akun utama jika tidak kosong |
| protoPayload.host | principal.asset.hostname | Nilai disalin secara langsung |
| httpRequest.serverIp, protoPayload.ip | principal.asset.ip | Digabungkan dengan server_ip dari httpRequest.serverIp atau protoPayload.ip |
| protoPayload.host | principal.hostname | Nilai disalin secara langsung |
| httpRequest.serverIp, protoPayload.ip | principal.ip | Digabungkan dengan server_ip dari httpRequest.serverIp atau protoPayload.ip |
| protoPayload.appId | principal.resource.attribute.labels | Digabungkan dengan appId_label yang berisi kunci "appId" dan nilai dari kolom |
| requestUser | principal.user.email_addresses | Digabungkan dengan requestUser jika cocok dengan pola email |
| security_result | security_result | Digabungkan dari security_result |
| resource.labels.forwarding_rule_name | security_result.rule_labels | Digabungkan dengan rule_label yang berisi kunci "forwarding_rule_name" dan nilai dari kolom |
| tingkat keseriusan, | security_result.severity | Disetel ke tingkat keparahan jika cocok dengan (?i)ERROR|CRITICAL, INFORMATIONAL jika cocok dengan (?i)INFO, MEDIUM jika cocok dengan (?i)WARN, LOW jika cocok dengan (?i)DEBUG, atau UNKNOWN_SEVERITY jika tidak cocok |
| jsonPayload.statusDetails | security_result.summary | Nilai disalin secara langsung |
| target | target | Diganti namanya dari target jika tidak kosong |
| resource.labels.backend_service_name | target.application | Nilai disalin secara langsung |
| httpRequest.remoteIp, jsonPayload.remoteIp | target.asset.ip | Digabungkan dengan remote_ip yang diekstrak dari httpRequest.remoteIp atau jsonPayload.remoteIp |
| resource.labels.project_id | target.cloud.project.name | Nilai disalin secara langsung |
| httpRequest.remoteIp, jsonPayload.remoteIp | target.ip | Digabungkan dengan remote_ip yang diekstrak dari httpRequest.remoteIp atau jsonPayload.remoteIp |
| resource.labels.zone | target.resource.attribute.cloud.availability_zone | Nilai disalin secara langsung |
| resource.labels.target_proxy_name, resource.labels.url_map_name | target.resource.attribute.labels | Digabungkan dengan label dari setiap sumber |
| resource.type | target.resource.type | Nilai disalin secara langsung |
| httpRequest.requestUrl | target.url | Nilai disalin secara langsung |
| metadata.product_name | Tetapkan ke "GCP_APP_ENGINE" | |
| metadata.vendor_name | Ditetapkan ke "GCP" |
Perlu bantuan lain? Dapatkan jawaban dari anggota Komunitas dan profesional Google SecOps.